<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2026-05-31T00:18:33+00:00</updated><id>/feed.xml</id><title type="html">Benshkies Blog</title><subtitle>A blog based on CTF&apos;s, Digital Forensics, Cybersecurity</subtitle><author><name>Koy</name></author><entry><title type="html">Nitroba - Email Harassment</title><link href="/2025/09/09/nitroba-email.html" rel="alternate" type="text/html" title="Nitroba - Email Harassment" /><published>2025-09-09T16:18:34+00:00</published><updated>2025-09-09T16:18:34+00:00</updated><id>/2025/09/09/nitroba-email</id><content type="html" xml:base="/2025/09/09/nitroba-email.html"><![CDATA[<h1 id="scenario">Scenario</h1>
<p>SOURCE: <a href="https://digitalcorpora.org/corpora/scenarios/nitroba-university-harassment-scenario/">Digital Corpora</a>
(Note: Because packet capture files contain timestamps for each packet, this scenario needs to have a date and time when it takes place. This scenario takes place in Summer 2008. The date and time stamps are not relevant in solving the problem set.)</p>

<p>You are a security administrator at the prestigious (and fictional) Nitroba State University.</p>

<p>Nitroba’s IT department received an email from Lily Tuckrige, a teacher in the Chemistry Department. Tuckrige has been receiving harassing emails and she suspects that they are being sent by a student in her class Chemistry 109, which she is teaching this summer. The email was received at Tuckridge’s personal email account, lilytuckrige@yahoo.com. She took a screenshot of the web browser and sent it in.</p>

<p>The system administrator who received the complaint wrote back to Tuckridge that Nitroba needed the full headers of the email message. Tuckridge responded by clicking the “Full message headers” button in Yahoo Mail and sent in another screen shot, this one with mail headers.</p>

<p>The mail header shows that the mail message originated from the IP address 140.247.62.34, which is a Nitroba student dorm room. Three women share the dorm room. Nitroba provides an Ethernet connection in every dorm room but not Wi-Fi access, so one of the women’s friends installed a Wi-Fi router in the room. There is no password on the Wi-Fi.</p>

<p>Because several email messages appear to come from the IP address, Nitroba decides to place a network sniffer on the ethernet port. All of the packets are logged. On Monday 7/21 Tuckridge received another harassing email. But this time instead of receiving it directly, the perpetrator sent it through a web-based service called “willselfdestruct.com.” The website briefly shows the message to Tuckridge, and then the website reports that the “Message Has Been Destroyed.”</p>

<p>You have been given the screen shots, the packets that were collected from the Ethernet tap, and the Chem 109 roster. Your job is to determine if one of the students in the class was responsible for the harassing email and to provide clear, conclusive evidence to support your conclusion.</p>

<h1 id="summary-of-what-we-know">Summary of What We Know</h1>
<p>Target: Lily Tuckrige</p>
<ul>
  <li>Email: lilytuckrige@yahoo.com
Harasser:</li>
  <li>IP 140.247.62.34</li>
  <li>nobody[@]nitroba.org</li>
  <li>3 women share the dorm room that the ip connects to: Alice, Barbara, Candice</li>
  <li>The room has a WiFi router installed by Barbaras boyfriend Kenny</li>
  <li>7/21 email sent from willselfdestruct[.]com</li>
  <li>3 Devices: A mac desktop, a Desktop PC, and  a laptop
<img src="\assets\images\nitroba-diagram.png" alt="Nitroba Diagram" /></li>
</ul>

<h1 id="investigation">Investigation</h1>
<p>Using the filter on the dorm ip: 140.247.62.34 we can find a one device connecting to it.</p>
<h2 id="apple-mac-device">Apple Mac Device:</h2>
<ul>
  <li>MAC: 00:17:f2:e2:c0:ce</li>
  <li>IP: 192.168.15.4</li>
</ul>

<p>The Mac Device made a DNS query to www.willselfdestruct[.]com</p>

<table>
  <thead>
    <tr>
      <th>Src IP</th>
      <th>Dst IP</th>
      <th>Protocol</th>
      <th>Info</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>192.168.15.4</td>
      <td>192.168.1.254</td>
      <td>DNS</td>
      <td>Standard query 0x0000 A www.willselfdestruct.com)</td>
    </tr>
  </tbody>
</table>

<p>URL: hxxp://www[.]willselfdestruct.com/&lt;redacted&gt; found. Examining packets related to this url filtering on a POST request we find the HTML form submitted with the hostile message.</p>

<table>
  <thead>
    <tr>
      <th>Src IP</th>
      <th>Dst IP</th>
      <th>Protocol</th>
      <th>Info</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>192.168.15.4</td>
      <td>&lt;redacted&gt;</td>
      <td>HTTP</td>
      <td>GET &lt;redacted&gt;HTTP/1.1</td>
    </tr>
    <tr>
      <td>192.168.15.4</td>
      <td>&lt;redacted&gt;</td>
      <td>HTTP</td>
      <td>POST &lt;redacted&gt; HTTP/1.1  (application/x-www-form-urlencoded)</td>
    </tr>
  </tbody>
</table>

<p><img src="\assets\images\html-form-selfdestruct.png" alt="HTML FORM" /></p>

<p>This is conclusive evidence that this device created and sent this self destruct message but we need to find who this IP belongs to.</p>

<p>Another email sent using sendanonymousemail.net/send.php as well as a new email “the_whole_world_is_watching@nitroba.org”</p>

<table>
  <thead>
    <tr>
      <th>Src IP</th>
      <th>Dst IP</th>
      <th>Protocol</th>
      <th>Info</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>192.168.15.4</td>
      <td>&lt;redacted&gt;</td>
      <td>HTTP</td>
      <td>POST /send.php HTTP/1.1  (application/x-www-form-urlencoded)</td>
    </tr>
  </tbody>
</table>

<p>Hotel information used by the harasser:</p>

<table>
  <thead>
    <tr>
      <th>Src IP</th>
      <th>Dst IP</th>
      <th>Protocol</th>
      <th>Info</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>192.168.15.4</td>
      <td>&lt;redacted&gt;</td>
      <td>HTTP</td>
      <td>POST /App/ViewHotelDetails?z=b97d&amp;r=aq&amp;availabilityRequestOnly=true&amp;fromDetailsLightbox=false HTTP/1.1  (application/x-www-form-urlencoded)</td>
    </tr>
  </tbody>
</table>

<p>It looks like the user signed into their gmail at one point. Looking for gmail we see that there are a couple packets with user id present in the cookies.</p>

<table>
  <thead>
    <tr>
      <th>Src IP</th>
      <th>Dst IP</th>
      <th>Protocol</th>
      <th>Info</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>192.168.15.4</td>
      <td>&lt;redacted&gt;</td>
      <td>HTTP</td>
      <td>GET /calendar/render?utm_campaign=en&amp;utm_source=en-ha-na-us-bk&amp;utm_medium=ha&amp;utm_term=google+calendar&amp;auth=DQAAAHAAAAA2jRol_d6eqNta6cIsYOASXiZFYMBTwdPcfzNQ24Qd0nZk837TiFwZuF-_zmFJv9UCMI1Hau3HvfR1-t3bfWj7AesmzsMkDPijjxRrfQdoDLmTsZFz_eXV7ghw6iFvaUuLKeDM4CzM1Z7yPw9jP4-V&amp;<strong>gausr</strong>=&lt;REDACTED&gt;** HTTP/1.1</td>
    </tr>
  </tbody>
</table>

<p>&lt;REDACTED EMAIL&gt; is none other than &lt;REDACTED&gt; from Lily Tuckrige’s class</p>

<p>If you want the answers or would like to know more about my thought process, feel free to reach out to me on <a href="https://www.linkedin.com/in/koy-bennion/">LinkedIn</a></p>]]></content><author><name>Benshkies</name></author><category term="dfir" /><category term="digital-corpora" /><summary type="html"><![CDATA[Scenario SOURCE: Digital Corpora (Note: Because packet capture files contain timestamps for each packet, this scenario needs to have a date and time when it takes place. This scenario takes place in Summer 2008. The date and time stamps are not relevant in solving the problem set.)]]></summary></entry><entry><title type="html">DFIRLABS: 2-Layer Security</title><link href="/2025/08/29/dfir-labs-2-layer-security.html" rel="alternate" type="text/html" title="DFIRLABS: 2-Layer Security" /><published>2025-08-29T00:15:25+00:00</published><updated>2025-08-29T00:15:25+00:00</updated><id>/2025/08/29/dfir-labs-2-layer-security</id><content type="html" xml:base="/2025/08/29/dfir-labs-2-layer-security.html"><![CDATA[<p>At the beginning of the challenge, you can quickly realize that we are dealing with a Linux filesystem. Looking through the folders to see if we have any suspicious files we see recycle.bin. For those with a Windows background this may look familiar but remember that we are in a Linux system. Linux does not have a recycle bin and handles recycling files very differently. So lets mark that as suspicious and see if there is anything else on the system. After searching the rest of the files and folders it doesnt look like there is much else to be had.</p>

<h2 id="zsh-history">ZSH History</h2>
<p>A key artifact in Linux forensics is the bash history. In this case it will actually be the zsh_history since they are using the zsh shell. Printing the history to the screen we can quickly tell that some sus things have been happening:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> ~
<span class="nb">cd </span>Desktop
<span class="nb">ls
</span>clear
<span class="nb">cd</span> ../../../../../../../../
<span class="nb">cd</span> /var/log
<span class="nb">cd</span> ~
<span class="nb">sudo </span>apt <span class="nb">install </span>curl
curl https://pastebin.com/raw/awhuFZse <span class="nt">-0</span> tienbip.txt
<span class="nv">LESSCLOSE</span><span class="o">=</span>/usr/bin/lesspipe %s %s
<span class="nb">cd</span> -
<span class="nb">cd </span>Desktop
<span class="nb">ls
</span>gpg <span class="nt">--quick-gen-key</span> Cocainit
gpg <span class="nt">--quick-gen-key</span> VNvodich
gpg <span class="nt">--quick-gen-key</span> Siuuuuuu
<span class="nb">ls
</span>gpg <span class="nt">-er</span> VNvodich RestrictedAccess.pdf
<span class="nb">ls
rm</span> <span class="nt">-rf</span> RestrictedAccess.pdf
<span class="nb">cat</span> /etc/shadow | <span class="nb">grep </span>idek<span class="o">{</span>
<span class="nb">cat</span> /etc/shadow | <span class="nb">grep</span> <span class="s2">"idek{"</span>
<span class="nb">mv </span>RestrictedAccess.pdf.gpg <span class="si">$(</span><span class="nb">cat</span> /dev/urandom | <span class="nb">tr</span> <span class="nt">-dc</span> <span class="s1">'a-zA-Z0-9'</span> | <span class="nb">fold</span> <span class="nt">-w</span> 5 | <span class="nb">head</span> <span class="nt">-n</span> 1<span class="si">)</span>
pwsh
<span class="nb">ls
mv </span>T3C4U.SOS recycle.bin
reboot
</code></pre></div></div>
<p>The first few lines are whatever, but then we start curl-ing for a pastebin file. Very suspicious. As we go on, it looks like the user generates gpg keys and then encrypts the file <code class="language-plaintext highlighter-rouge">RestrictedAccess.pdf</code> using VNvodich’s gpg key (1st layer in the 2-layer encryption). Afterwards the file is moved to a randomly generated folder name. After that they enter into powershell (<code class="language-plaintext highlighter-rouge">pwsh</code>) powershell on linux is not really normal but not unheard of. So fortunately we can look at those logs as well in <code class="language-plaintext highlighter-rouge">home\kalilinux\.local\share\powershell\PSReadLine\ConsoleHost_history.txt</code></p>

<h2 id="powershell-history">Powershell History</h2>
<p>Opening the ConsoleHost_history.txt file shows us the next steps this user did to encrypt the file:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ls</span><span class="w">
</span><span class="nx">whoami</span><span class="w">
</span><span class="p">(</span><span class="w"> </span><span class="n">nEw-oBJECT</span><span class="w"> </span><span class="nx">syStem.io.sTrEamReadeR</span><span class="p">(</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">nEw-oBJECT</span><span class="w"> </span><span class="nx">sysTeM.iO.COMPReSsioN.deflAtEsTREaM</span><span class="p">([</span><span class="n">sySTEM.iO.MeMoRyStreaM</span><span class="p">]</span><span class="w"> </span><span class="p">[</span><span class="n">ConVert</span><span class="p">]::</span><span class="n">froMbaSe64striNg</span><span class="p">(</span><span class="s1">'hVXbbuJIEH2PlH/omZfYGrAwtxCkPASWXLTDgGL2Mot46MENeGLaqN3WLov873uqbQPGiRZhulz3OlXVBKM/mWVZnw/tRnpw79JDs5Me2l3QOF0XNJ4mydqge+mh1cJ5i5Me6DQhAkVakLjQwLcNAXy1yB9em2QLaYto2HVIk94Rpw0dF2eLYkDWBN2ENxeOwepQCumBEqI3eqALWQvcDs42niY9FA+vYN+mn+srdsPyT3p9dX1VvHyfjoVcqv1OR4rd0ysX8ZjLm9oNXwsfrG/i7/rkx0+x1Mzbx1psHU8sExXovTM0dmvFd1BnJeNDKUS84WCTQ+eXIN5FsbBsKEBPGaKSjPAHey3iLKNjgs5McRmvIrV9DCQPYZ7rlVxkOVSCXXxOnGDFLJhNud7Y7CxvSm8QRss3ku5CHkgTq8YaNVbiOF+FXMP4ohCYn0ID9JTK5bsNcAt2G6HGkS8W/f5wMLw2lThT7vuBXKPo+cdIwzzXy+3/gnEVsxMIEG+zHCyQ/f6r4P5DGBpdquwxCIXzmIThN74VF0BBHCWakMm8lnTZF/ZTThxv4uG4vqJyR5M3+/+xptlScKCF8oQ2ru7JlSmSQoC2FyejuacV6l3kTcoEdjHFA7EOJHtv3gze+BnjKecExvsAQ2AVoeeTRO8S4sCXzzF/+wwFrRJRY1Oa+VOrXiYOpb6gVpYRUEInSlKBpMCOE850VAAMI/+jGaY2mzgEcME0c+kF/wowtVk+9gfqEPWRUljk+ljEMRSPQWWk2SpKpP/J9OqyQT+U4G9ldlqZhNPAU8AsaJEttVRvSr7T4+AXnRpJn8zMOGWJPix1EEnmIUWpw/0wkjqQyQV+NDOfKoOKjsMXtuGhgCrL6LIf/b4B5oHQIz7Os+HPp7tWvXqOYwyDZqebA3/GfO/GyOAwiN+zJygVK+s9UwLNnlkToSJzY4FcJTKDYJQFJzJ3OB9u/VDoQSBp2aF7thDTYn/APi3mVx5rU+ws2GbD6R679N7FeL4WZ2KwZ/udsOZxtnbFPkxpl8oL88G/BNWo6y+Am9VNt7/ThDsvv+PKOAGdG8OT4FrkAETHjK2nwsepT3apRsE+Ku9XsaflQF5o3dkcmjJUtMR2XNwYZeNsz8/+tYbRdpdo8czjjVVM2Ez8ox2kHVF/MGe/zR57DpLOhgtX4eVM3di2o8Q05EthWfPlM39ddO++ZMRtQbiNW7s292avL/JpkbFadxU7t9Et9N3G0UXFsF0x7BVxekezaryuzez/AA=='</span><span class="w"> </span><span class="p">),</span><span class="w"> </span><span class="p">[</span><span class="n">SyStem.IO.comPreSSION.cOmpreSSIONModE</span><span class="p">]::</span><span class="n">DEcOmPREsS</span><span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="p">),</span><span class="w"> </span><span class="p">[</span><span class="n">text.ENcodiNg</span><span class="p">]::</span><span class="n">AScII</span><span class="p">))</span><span class="o">.</span><span class="nf">ReAdToend</span><span class="p">()</span><span class="o">|&amp;</span><span class="p">(</span><span class="w"> </span><span class="nv">$sHeLLid</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">+</span><span class="nv">$shELliD</span><span class="p">[</span><span class="mi">13</span><span class="p">]</span><span class="o">+</span><span class="s1">'x'</span><span class="p">)</span><span class="w">
</span><span class="n">Encryption</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="o">.</span><span class="nx">/T3C4U</span><span class="w">
</span><span class="n">Remove-Item</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="o">.</span><span class="nx">/T3C4U</span><span class="w"> </span><span class="nt">-Force</span><span class="w"> </span><span class="nt">-Recurse</span><span class="w">
</span><span class="kr">exit</span><span class="w">
</span></code></pre></div></div>

<p>Oof what the flip is that huge blob! Its definitely base64 encoded so lets decode it. Using the From Base64 and Raw Inflate recipe in CyberChef gives us:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">iEX</span><span class="w"> </span><span class="p">(((</span><span class="s2">"{40}{19}{25}{46}{15}{11}{41}{20}{14}{48}{33}{47}{37}{35}{2}{1}{31}{23}{18}{8}{45}{9}{39}{28}{24}{43}{38}{27}{53}{13}{36}{49}{16}{30}{17}{26}{21}{12}{0}{51}{4}{6}{10}{50}{5}{32}{34}{52}{42}{22}{29}{3}{44}{7}"</span><span class="nt">-f</span><span class="w"> </span><span class="s1">'        }

        YPMencryptor = YPMaesMan'</span><span class="p">,</span><span class="s1">'aged = New-Object System.Security.Cryptograp'</span><span class="p">,</span><span class="s1">'  YPMaesMan'</span><span class="p">,</span><span class="s1">'{
        YPMshaManaged.Dispose()
 '</span><span class="p">,</span><span class="s1">'r()
        YPMencryptedBytes = YPMencryptor.TransformFinal'</span><span class="p">,</span><span class="s1">'edBytes
        YPMaesManaged.Dispose()
                
        if (YPMPath) {
         '</span><span class="p">,</span><span class="s1">'Block(YPMplainBytes, 0, YPMplainBytes.Length)
        YPMen'</span><span class="p">,</span><span class="s1">'se()
    }
}'</span><span class="p">,</span><span class="s1">'raphy.CipherMode]::CBC
'</span><span class="p">,</span><span class="s1">'ed.Padding = [System.Security.Cryptography.PaddingMode]::Z'</span><span class="p">,</span><span class="s1">'cryptedBytes = YPMaesManaged'</span><span class="p">,</span><span class="s1">'m
    ('</span><span class="p">,</span><span class="s1">'::ReadAllBytes(YPMFile.FullName)
            YPMoutPath = YPMFile.FullName + jnO.SOSjnO
'</span><span class="p">,</span><span class="s1">'sEOk))
                
        if (Y'</span><span class="p">,</span><span class="s1">'arameterSetName = jnOCryptFilejnO)]
        [String]YPMPath
    )

    Begin {
        YPMshaMan'</span><span class="p">,</span><span class="s1">'ra'</span><span class="p">,</span><span class="s1">'M'</span><span class="p">,</span><span class="s1">'
             '</span><span class="p">,</span><span class="s1">'ystem.Security.Cryptog'</span><span class="p">,</span><span class="s1">'()]
    [Outpu'</span><span class="p">,</span><span class="s1">'(Mandatory = YPMtrue, P'</span><span class="p">,</span><span class="s1">' = [System.IO.File]'</span><span class="p">,</span><span class="s1">'e
            return jnOFile encrypted to YPMoutP'</span><span class="p">,</span><span class="s1">'d
        YPMaesManaged.Mode = [S'</span><span class="p">,</span><span class="s1">'sManaged.BlockSize'</span><span class="p">,</span><span class="s1">'t'</span><span class="p">,</span><span class="s1">'   Write-Error -Message jnOFile not found!jnO
                break
            }
            YPMplainBytes'</span><span class="p">,</span><span class="s1">' '</span><span class="p">,</span><span class="s1">'      YPMae'</span><span class="p">,</span><span class="s1">'athjnO
        }
    }


    End '</span><span class="p">,</span><span class="s1">'Path -ErrorAction SilentlyContinue
            if (!YPMFile.FullName) {
'</span><span class="p">,</span><span class="s1">'hy.AesManage'</span><span class="p">,</span><span class="s1">'   [System.IO.File]::WriteA'</span><span class="p">,</span><span class="s1">'stem.'</span><span class="p">,</span><span class="s1">'llBytes(YPMoutPath, YPMencryptedBytes)
      '</span><span class="p">,</span><span class="s1">'256Managed
      '</span><span class="p">,</span><span class="s1">'PMPath) {
            YPMFile = G'</span><span class="p">,</span><span class="s1">'ography.SHA'</span><span class="p">,</span><span class="s1">'28
'</span><span class="p">,</span><span class="s1">'eros
  '</span><span class="p">,</span><span class="s1">'function Encryption {
    [CmdletBinding'</span><span class="p">,</span><span class="s1">'
        [Parameter'</span><span class="p">,</span><span class="s1">'= YPMFile.LastWriteTim'</span><span class="p">,</span><span class="s1">' = 1'</span><span class="p">,</span><span class="s1">'       YPMaesManaged.Dispo'</span><span class="p">,</span><span class="s1">'
        YPMaesManag'</span><span class="p">,</span><span class="s1">'Type([string])]
    Pa'</span><span class="p">,</span><span class="s1">'Security.Crypt'</span><span class="p">,</span><span class="s1">'aged = New-Object Sy'</span><span class="p">,</span><span class="s1">'et-Item -Path YP'</span><span class="p">,</span><span class="s1">'.IV + YPMencrypt'</span><span class="p">,</span><span class="s1">'aged.CreateEncrypto'</span><span class="p">,</span><span class="s1">'      (Get-Item YPMoutPath).LastWriteTime '</span><span class="p">,</span><span class="s1">'       YPMaesManaged.KeySize = 256
    }

    Process {
        YPMaesManaged.Key = YPMshaManaged.ComputeHash([System.Text.Encoding]::UTF8.GetBytes(EOkYPMencryptedByte'</span><span class="p">))</span><span class="o">.</span><span class="nf">rePlace</span><span class="p">(([</span><span class="n">cHaR</span><span class="p">]</span><span class="mi">69</span><span class="o">+</span><span class="p">[</span><span class="n">cHaR</span><span class="p">]</span><span class="mi">79</span><span class="o">+</span><span class="p">[</span><span class="n">cHaR</span><span class="p">]</span><span class="mi">107</span><span class="p">),[</span><span class="n">STRInG</span><span class="p">][</span><span class="n">cHaR</span><span class="p">]</span><span class="mi">39</span><span class="p">)</span><span class="o">.</span><span class="nf">rePlace</span><span class="p">(([</span><span class="n">cHaR</span><span class="p">]</span><span class="mi">106</span><span class="o">+</span><span class="p">[</span><span class="n">cHaR</span><span class="p">]</span><span class="mi">110</span><span class="o">+</span><span class="p">[</span><span class="n">cHaR</span><span class="p">]</span><span class="mi">79</span><span class="p">),[</span><span class="n">STRInG</span><span class="p">][</span><span class="n">cHaR</span><span class="p">]</span><span class="mi">34</span><span class="p">)</span><span class="o">.</span><span class="nf">rePlace</span><span class="p">(([</span><span class="n">cHaR</span><span class="p">]</span><span class="mi">89</span><span class="o">+</span><span class="p">[</span><span class="n">cHaR</span><span class="p">]</span><span class="mi">80</span><span class="o">+</span><span class="p">[</span><span class="n">cHaR</span><span class="p">]</span><span class="mi">77</span><span class="p">),[</span><span class="n">STRInG</span><span class="p">][</span><span class="n">cHaR</span><span class="p">]</span><span class="mi">36</span><span class="p">)</span><span class="w"> </span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>Not much better. Lets see if ChatGPT can help. After a few failed prompts and some guidance chat helped us put this all back together:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">function</span><span class="w"> </span><span class="nf">Encryption</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="p">[</span><span class="n">CmdletBinding</span><span class="p">()]</span><span class="w">
    </span><span class="p">[</span><span class="n">OutputType</span><span class="p">([</span><span class="n">string</span><span class="p">])]</span><span class="w">
    </span><span class="kr">Param</span><span class="w">
    </span><span class="p">(</span><span class="w">
        </span><span class="p">[</span><span class="n">Parameter</span><span class="p">(</span><span class="n">Mandatory</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">$true</span><span class="p">,</span><span class="w"> </span><span class="n">ParameterSetName</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"CryptFile"</span><span class="p">)]</span><span class="w">
        </span><span class="p">[</span><span class="n">String</span><span class="p">]</span><span class="nv">$Path</span><span class="w">
    </span><span class="p">)</span><span class="w">

    </span><span class="kr">Begin</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nv">$shaManaged</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">New-Object</span><span class="w"> </span><span class="nx">System.Security.Cryptography.SHA256Managed</span><span class="w">
        </span><span class="nv">$aesManaged</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">New-Object</span><span class="w"> </span><span class="nx">System.Security.Cryptography.AesManaged</span><span class="w">
        </span><span class="nv">$aesManaged</span><span class="o">.</span><span class="nf">Mode</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="n">System.Security.Cryptography.CipherMode</span><span class="p">]::</span><span class="n">CBC</span><span class="w">

        </span><span class="nv">$aesManaged</span><span class="o">.</span><span class="nf">Padding</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="n">System.Security.Cryptography.PaddingMode</span><span class="p">]::</span><span class="n">Zeros</span><span class="w">
        </span><span class="nv">$aesManaged</span><span class="o">.</span><span class="nf">BlockSize</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">128</span><span class="w">
        </span><span class="nv">$aesManaged</span><span class="o">.</span><span class="nf">KeySize</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">256</span><span class="w">
    </span><span class="p">}</span><span class="w">

    </span><span class="kr">Process</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nv">$aesManaged</span><span class="o">.</span><span class="nf">Key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$shaManaged</span><span class="o">.</span><span class="nf">ComputeHash</span><span class="p">([</span><span class="n">System.Text.Encoding</span><span class="p">]::</span><span class="nx">UTF8.GetBytes</span><span class="p">(</span><span class="s1">'$encryptedBytes'</span><span class="p">))</span><span class="w">

        </span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$Path</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="nv">$File</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-Item</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="nv">$Path</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">SilentlyContinue</span><span class="w">
            </span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="nv">$File</span><span class="o">.</span><span class="nf">FullName</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">

                </span><span class="n">Write-Error</span><span class="w"> </span><span class="nt">-Message</span><span class="w"> </span><span class="s2">"File not found!"</span><span class="w">
                </span><span class="kr">break</span><span class="w">
            </span><span class="p">}</span><span class="w">
            </span><span class="nv">$plainBytes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="n">System.IO.File</span><span class="p">]::</span><span class="n">ReadAllBytes</span><span class="p">(</span><span class="nv">$File</span><span class="o">.</span><span class="nf">FullName</span><span class="p">)</span><span class="w">
            </span><span class="nv">$outPath</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$File</span><span class="o">.</span><span class="nf">FullName</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">".SOS."</span><span class="w">
        </span><span class="p">}</span><span class="w">

        </span><span class="nv">$encryptor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$aesManaged</span><span class="o">.</span><span class="nf">CreateEncryptor</span><span class="p">()</span><span class="w">
        </span><span class="nv">$encryptedBytes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$encryptor</span><span class="o">.</span><span class="nf">TransformFinalBlock</span><span class="p">(</span><span class="nv">$plainBytes</span><span class="p">,</span><span class="w"> </span><span class="nx">0</span><span class="p">,</span><span class="w"> </span><span class="nv">$plainBytes</span><span class="o">.</span><span class="nf">Length</span><span class="p">)</span><span class="w">
        </span><span class="nv">$encryptedBytes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$aesManaged</span><span class="o">.</span><span class="nf">IV</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nv">$encryptedBytes</span><span class="w">
        </span><span class="nv">$aesManaged</span><span class="o">.</span><span class="nf">Dispose</span><span class="p">()</span><span class="w">

        </span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$Path</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="p">[</span><span class="n">System.IO.File</span><span class="p">]::</span><span class="n">WriteAllBytes</span><span class="p">(</span><span class="nv">$outPath</span><span class="p">,</span><span class="w"> </span><span class="nv">$encryptedBytes</span><span class="p">)</span><span class="w">
            </span><span class="p">(</span><span class="n">Get-Item</span><span class="w"> </span><span class="nv">$outPath</span><span class="p">)</span><span class="o">.</span><span class="nf">LastWriteTime</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$File</span><span class="o">.</span><span class="nf">LastWriteTime</span><span class="w">
            </span><span class="kr">return</span><span class="w"> </span><span class="s2">"File encrypted to </span><span class="nv">$outPath</span><span class="s2">"</span><span class="w">
        </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">

    </span><span class="kr">End</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nv">$shaManaged</span><span class="o">.</span><span class="nf">Dispose</span><span class="p">()</span><span class="w">
        </span><span class="nv">$aesManaged</span><span class="o">.</span><span class="nf">Dispose</span><span class="p">()</span><span class="w">
    </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>So its an custom encryption algorithm. Although, ChatGPT says its kind of janky because in the laine where it sets the key the variable <code class="language-plaintext highlighter-rouge">$encryptedBytes</code> has not been set yet. In powershell this would be treated as an empty value, meaning that the key is actually just an empty string. LOL so now that we know the key, lets reverse the encryption. I had ChatGPT write me a function to do this:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">function</span><span class="w"> </span><span class="nf">Decryption</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="p">[</span><span class="n">CmdletBinding</span><span class="p">()]</span><span class="w">
    </span><span class="p">[</span><span class="n">OutputType</span><span class="p">([</span><span class="n">string</span><span class="p">])]</span><span class="w">
    </span><span class="kr">Param</span><span class="w">
    </span><span class="p">(</span><span class="w">
        </span><span class="p">[</span><span class="n">Parameter</span><span class="p">(</span><span class="n">Mandatory</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">$true</span><span class="p">,</span><span class="w"> </span><span class="n">ParameterSetName</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"DecryptFile"</span><span class="p">)]</span><span class="w">
        </span><span class="p">[</span><span class="n">String</span><span class="p">]</span><span class="nv">$Path</span><span class="w">
    </span><span class="p">)</span><span class="w">

    </span><span class="kr">Begin</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nv">$shaManaged</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">New-Object</span><span class="w"> </span><span class="nx">System.Security.Cryptography.SHA256Managed</span><span class="w">
        </span><span class="nv">$aesManaged</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">New-Object</span><span class="w"> </span><span class="nx">System.Security.Cryptography.AesManaged</span><span class="w">
        </span><span class="nv">$aesManaged</span><span class="o">.</span><span class="nf">Mode</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="n">System.Security.Cryptography.CipherMode</span><span class="p">]::</span><span class="n">CBC</span><span class="w">
        </span><span class="nv">$aesManaged</span><span class="o">.</span><span class="nf">Padding</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="n">System.Security.Cryptography.PaddingMode</span><span class="p">]::</span><span class="n">Zeros</span><span class="w">
        </span><span class="nv">$aesManaged</span><span class="o">.</span><span class="nf">BlockSize</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">128</span><span class="w">
        </span><span class="nv">$aesManaged</span><span class="o">.</span><span class="nf">KeySize</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">256</span><span class="w">
    </span><span class="p">}</span><span class="w">
    
    </span><span class="kr">Process</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="c"># Generate the same key as the encryption function (uses literal '$encryptedBytes' string)</span><span class="w">
        </span><span class="nv">$aesManaged</span><span class="o">.</span><span class="nf">Key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$shaManaged</span><span class="o">.</span><span class="nf">ComputeHash</span><span class="p">([</span><span class="n">System.Text.Encoding</span><span class="p">]::</span><span class="nx">UTF8.GetBytes</span><span class="p">(</span><span class="s1">'$encryptedBytes'</span><span class="p">))</span><span class="w">
        
        </span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$Path</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="nv">$File</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-Item</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="nv">$Path</span><span class="w"> </span><span class="nt">-ErrorAction</span><span class="w"> </span><span class="nx">SilentlyContinue</span><span class="w">
            </span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="nv">$File</span><span class="o">.</span><span class="nf">FullName</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
                </span><span class="n">Write-Error</span><span class="w"> </span><span class="nt">-Message</span><span class="w"> </span><span class="s2">"File not found!"</span><span class="w">
                </span><span class="kr">break</span><span class="w">
            </span><span class="p">}</span><span class="w">
            
            </span><span class="c"># Read the encrypted file</span><span class="w">
            </span><span class="nv">$encryptedBytes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="n">System.IO.File</span><span class="p">]::</span><span class="n">ReadAllBytes</span><span class="p">(</span><span class="nv">$File</span><span class="o">.</span><span class="nf">FullName</span><span class="p">)</span><span class="w">
            
            </span><span class="c"># Extract IV (first 16 bytes) and encrypted data (remaining bytes)</span><span class="w">
            </span><span class="nv">$iv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$encryptedBytes</span><span class="p">[</span><span class="mi">0</span><span class="o">..</span><span class="mi">15</span><span class="p">]</span><span class="w">
            </span><span class="nv">$encryptedData</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$encryptedBytes</span><span class="p">[</span><span class="mi">16</span><span class="o">..</span><span class="p">(</span><span class="nv">$encryptedBytes</span><span class="o">.</span><span class="nf">Length</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">)]</span><span class="w">
            
            </span><span class="c"># Set the IV</span><span class="w">
            </span><span class="nv">$aesManaged</span><span class="o">.</span><span class="nf">IV</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$iv</span><span class="w">
            
            </span><span class="c"># Create output path (remove .SOS. extension)</span><span class="w">
            </span><span class="nv">$outPath</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$File</span><span class="o">.</span><span class="nf">FullName</span><span class="w"> </span><span class="o">-replace</span><span class="w"> </span><span class="s1">'\.SOS\.$'</span><span class="p">,</span><span class="w"> </span><span class="s1">''</span><span class="w">
            
            </span><span class="c"># If the file doesn't end with .SOS., just add .decrypted</span><span class="w">
            </span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$outPath</span><span class="w"> </span><span class="o">-eq</span><span class="w"> </span><span class="nv">$File</span><span class="o">.</span><span class="nf">FullName</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
                </span><span class="nv">$outPath</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$File</span><span class="o">.</span><span class="nf">FullName</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">".decrypted"</span><span class="w">
            </span><span class="p">}</span><span class="w">
        </span><span class="p">}</span><span class="w">
        
        </span><span class="c"># Decrypt the data</span><span class="w">
        </span><span class="nv">$decryptor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$aesManaged</span><span class="o">.</span><span class="nf">CreateDecryptor</span><span class="p">()</span><span class="w">
        </span><span class="nv">$decryptedBytes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$decryptor</span><span class="o">.</span><span class="nf">TransformFinalBlock</span><span class="p">(</span><span class="nv">$encryptedData</span><span class="p">,</span><span class="w"> </span><span class="nx">0</span><span class="p">,</span><span class="w"> </span><span class="nv">$encryptedData</span><span class="o">.</span><span class="nf">Length</span><span class="p">)</span><span class="w">
        
        </span><span class="c"># Remove zero padding (since we used PaddingMode.Zeros)</span><span class="w">
        </span><span class="c"># Find the last non-zero byte</span><span class="w">
        </span><span class="nv">$lastNonZeroIndex</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nt">-1</span><span class="w">
        </span><span class="kr">for</span><span class="w"> </span><span class="p">(</span><span class="nv">$i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$decryptedBytes</span><span class="o">.</span><span class="nf">Length</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="nv">$i</span><span class="w"> </span><span class="o">-ge</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nv">$i</span><span class="o">--</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$decryptedBytes</span><span class="p">[</span><span class="nv">$i</span><span class="p">]</span><span class="w"> </span><span class="o">-ne</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
                </span><span class="nv">$lastNonZeroIndex</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$i</span><span class="w">
                </span><span class="kr">break</span><span class="w">
            </span><span class="p">}</span><span class="w">
        </span><span class="p">}</span><span class="w">
        
        </span><span class="c"># If we found non-zero bytes, trim to that point, otherwise keep original</span><span class="w">
        </span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$lastNonZeroIndex</span><span class="w"> </span><span class="o">-ge</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="nv">$trimmedBytes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$decryptedBytes</span><span class="p">[</span><span class="mi">0</span><span class="o">..</span><span class="nv">$lastNonZeroIndex</span><span class="p">]</span><span class="w">
        </span><span class="p">}</span><span class="w"> </span><span class="kr">else</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="nv">$trimmedBytes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$decryptedBytes</span><span class="w">
        </span><span class="p">}</span><span class="w">
        
        </span><span class="nv">$aesManaged</span><span class="o">.</span><span class="nf">Dispose</span><span class="p">()</span><span class="w">

        </span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$Path</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="p">[</span><span class="n">System.IO.File</span><span class="p">]::</span><span class="n">WriteAllBytes</span><span class="p">(</span><span class="nv">$outPath</span><span class="p">,</span><span class="w"> </span><span class="nv">$trimmedBytes</span><span class="p">)</span><span class="w">
            </span><span class="p">(</span><span class="n">Get-Item</span><span class="w"> </span><span class="nv">$outPath</span><span class="p">)</span><span class="o">.</span><span class="nf">LastWriteTime</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$File</span><span class="o">.</span><span class="nf">LastWriteTime</span><span class="w">
            </span><span class="kr">return</span><span class="w"> </span><span class="s2">"File decrypted to </span><span class="nv">$outPath</span><span class="s2">"</span><span class="w">
        </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">

    </span><span class="kr">End</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nv">$shaManaged</span><span class="o">.</span><span class="nf">Dispose</span><span class="p">()</span><span class="w">
        </span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$aesManaged</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="nv">$aesManaged</span><span class="o">.</span><span class="nf">Dispose</span><span class="p">()</span><span class="w">
        </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Ok so with this function, lets try and decrypt this last layer of encryption.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># &lt;paste code into powershell&gt;</span><span class="w">
</span><span class="n">Decyrption</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="nx">\Evidence\recycle.bin</span><span class="w">
</span></code></pre></div></div>
<p>So we really wont know that its decrypted this 1st layer until we try to decrypt the next layer.</p>

<h2 id="gpg-decryption">GPG Decryption</h2>
<p>Usually GPG decyption is pretty simple if you have access to the system and user account (and password if one was set for the key) but here with an offline copy its a little more janky. We know that the .gnupg folder is in the <code class="language-plaintext highlighter-rouge">/home/kalilinux</code> folder and <code class="language-plaintext highlighter-rouge">gpg</code> will let you specify a home directory if needed. So when I tried to do that, it gave me a bunch of errors and didnt like it. So instead I did this:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir</span> ~/gnupg-temp
<span class="nb">cp</span> <span class="nt">-r</span> /home/kalilinux/.gnupg/<span class="k">*</span> ~/gnupg-temp/
<span class="nb">chmod </span>700 ~/gnupg-temp
gpg <span class="nt">--homedir</span> ~/gnupg-temp <span class="nt">--output</span> decrypted_file.pdf <span class="nt">--decrypt</span> /Evidence/recycle.bin.decrypted
</code></pre></div></div>
<p>You should see some output similar to this:
<img src="\assets\images\2-layer-screenshot.png" alt="2-layer" />
Afterwards you can open the file and the flag is right there in the photo
FLAG: <code class="language-plaintext highlighter-rouge">idek{Cr34t1n9_ch4ll3ngEs_6_d4ys_6_n1gts_w1th0ut_sl33p}</code></p>

<p>This challenge was really cool, I havent ever messed with gpg keys so it was a fun way to learn how to manipulate them to reverse the encryption.</p>]]></content><author><name>Benshkies</name></author><category term="dfir" /><category term="ctf-dfirlabs" /><summary type="html"><![CDATA[At the beginning of the challenge, you can quickly realize that we are dealing with a Linux filesystem. Looking through the folders to see if we have any suspicious files we see recycle.bin. For those with a Windows background this may look familiar but remember that we are in a Linux system. Linux does not have a recycle bin and handles recycling files very differently. So lets mark that as suspicious and see if there is anything else on the system. After searching the rest of the files and folders it doesnt look like there is much else to be had.]]></summary></entry><entry><title type="html">DFIRLABS: Trinity of Secrets</title><link href="/2025/07/15/dfir-labs-trinity-of-secrets.html" rel="alternate" type="text/html" title="DFIRLABS: Trinity of Secrets" /><published>2025-07-15T19:36:34+00:00</published><updated>2025-07-15T19:36:34+00:00</updated><id>/2025/07/15/dfir-labs-trinity-of-secrets</id><content type="html" xml:base="/2025/07/15/dfir-labs-trinity-of-secrets.html"><![CDATA[<p><img src="/assets/images/trinity-of-secrets.png" alt="ChatGPT Trinity of Secrets" /> <em>(Image generated by ChatGPT)</em>
Unzipping the file shows another raw file, so lets search for a profile in volatility</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ vol.py -f DFIRLABS.raw imageinfo
Volatility Foundation Volatility Framework 2.6.1
INFO    : volatility.debug    : Determining profile based on KDBG search...
          Suggested Profile(s) : Win10x64_19041
                     AS Layer1 : SkipDuplicatesAMD64PagedMemory (Kernel AS)
                     AS Layer2 : FileAddressSpace (/home/sansforensics/DFIRLABS.raw)
                      PAE type : No PAE
                           DTB : 0x1aa000L
                          KDBG : 0xf80681a00b20L
          Number of Processors : 4
     Image Type (Service Pack) : 0
                KPCR for CPU 0 : 0xfffff8067dee2000L
                KPCR for CPU 1 : 0xffffa2814c5a0000L
                KPCR for CPU 2 : 0xffffa2814bfa1000L
                KPCR for CPU 3 : 0xffffa2814c30e000L
             KUSER_SHARED_DATA : 0xfffff78000000000L
           Image date and time : 2024-05-22 16:22:06 UTC+0000
     Image local date and time : 2024-05-22 21:52:06 +0530
</code></pre></div></div>
<p>Looks like our image profile will be <code class="language-plaintext highlighter-rouge">Win10x64_19041</code></p>

<p>Since its windows 10 its possible volatility 3 will be better but since im already in vol2 ill see if i can grab some things. From cmdlist:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Code.exe pid:   6252
Command line : "C:\Users\User\AppData\Local\Programs\Microsoft VS Code\Code.exe" 
************************************************************************
Discord.exe pid:   7672
Command line : "C:\Users\User\AppData\Local\Discord\app-1.0.9147\Discord.exe" 
************************************************************************
OneDrive.exe pid:   7384
Command line : "C:\Users\User\AppData\Local\Microsoft\OneDrive\OneDrive.exe" /background
</code></pre></div></div>

<p>VSCode is a possible place for looking. Possible malware or other files
Discord is another one that we could probably extract some text maybe?
OneDrive could just be used from a start up process but worth verifying</p>

<p>Since VSCode was used quite a bit, there are possibly files that we can uncover so lets use filescan.</p>

<p>There wasnt a lot in there for me to see for now at least. Might come back to it to see if there was anything else.</p>

<p>Another avenue for discovering potential files is malfind. Running that module shows me MsMpEng.exe multiple times so lets do some research to see if this is a normal program. According to google, “MsMpEng.exe is the <strong>Antimalware Service Executable, a core component of Windows Defender</strong>” So if this is getting activated its possible there could be a malicious file somewhere. The rest of the mentions in the malfind output arent too interesting at least to my knowledge.</p>

<p>The part of the riddle says it lies in your code. But I cant find anything related to VsCode or any files that relate to that. So i think i missed something in filescan so lets go back there and start grepping.</p>

<p>Grepping for “Code” I see git.log which could be helpful.</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0x0000cb0f5ef608b0  32761      1 -W-rw- \Device\HarddiskVolume1\Users\User\AppData\Roaming\Code\logs\20240522T215144\window1\exthost\vscode.git\Git.log
</code></pre></div></div>
<p>Also possibly interesting is this workspace state file</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0x0000cb0f58c54af0  32674      1 RW-rw- \Device\HarddiskVolume1\Users\User\AppData\Roaming\Code\User\workspaceStorage\1716390920783\state.vscdb
</code></pre></div></div>
<p>So lets dump those and see what we are working with:</p>

<p>For some reason they werent dumping with Vol2 but they do with vol3. After all that work there was nothing really to report from either of these.</p>

<p>With some guidance from the Admins, I was pointed to look for VSCode Backups. Doing some research on where these might be found, I found articles that said the backups or Hot Exits are  usually found in <code class="language-plaintext highlighter-rouge">\Users\&lt;User&gt;\AppData\Roaming\Code\Backups</code> and sure enough that path was in the <code class="language-plaintext highlighter-rouge">filescan</code> output. Dumping the virtual address:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">vol3</span><span class="w"> </span><span class="nt">-f</span><span class="w"> </span><span class="o">.</span><span class="nx">\trinity.raw</span><span class="w"> </span><span class="nt">-o</span><span class="w"> </span><span class="o">.</span><span class="nx">\</span><span class="w"> </span><span class="nx">dumpfiles</span><span class="w"> </span><span class="nt">--virtaddr</span><span class="w"> </span><span class="nx">0xcb0f58c6b890</span><span class="w">
</span></code></pre></div></div>
<p>Printing the files content to the screen shows:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>untitled:Untitled-1 {"typeId":""}
untitled:Untitled-2 {"typeId":""}
Function Decrypt(message, password)
    Dim key
    Dim i
    Dim encrypted_message
    Dim char

    key = Hash(password)

    For i = 1 To 10
        encrypted_message = ""
        For j = 1 To Len(message)
            char = Mid(message, j, 1)
            encrypted_message = encrypted_message &amp; Chr(Asc(char) Xor Asc(Mid(key, (i - 1) Mod Len(key) + 1, 1)))
        Next
        message = encrypted_message
    Next

    Encrypt = encrypted_message
End Function

Function Hash(text)
    Dim sha256
    Dim bytes
    Dim i

    Set sha256 = CreateObject("System.Security.Cryptography.SHA256Managed")
    bytes = sha256.ComputeHash_2((StrConv(text, vbFromUnicode)))

    Hash = ""
    For i = 1 To LenB(bytes)
        Hash = Hash &amp; Right("0" &amp; Hex(AscB(MidB(bytes, i, 1))), 2)
    Next
End Function

Dim password, ciphertext, decrypted
password = " "
ciphertext = " "
decrypted = Decrypt(ciphertext, password)
WScript.Echo "Decrypted:", decrypted


"""
Deep within the gamer's lore
Is a secret waiting to be unlocked

Find the file that holds the cached key
Maybe what you are looking for is data_3
It might hold the images that you seek

Conversations notified but left unseen.
And within the quiet pings, where alerts softly chime,
Another piece awaits, revealing the r1ddl3r's crime.
""" 
</code></pre></div></div>

<p>Looks to be a VBS file. I changed the files name to keep track of it but we may need to use this later on to decrypt a flag.</p>

<p><code class="language-plaintext highlighter-rouge">The gamers lore</code>, not sure about that, possibly a discord hint?
<code class="language-plaintext highlighter-rouge">A cached key related to data_3</code>, I remember some files had some of that appended to the end
The last part seems to hint at discord again.</p>

<p>Lol funny enough when i looked back at my screen from the filescan I saw <code class="language-plaintext highlighter-rouge">Users\User\AppData\Roaming\Code\Cache\Cache_Data\data_3</code> so lets dump that. Also of note is some discord data that has that so we will dump that as well</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0xcb0f58c70520  \Users\User\AppData\Roaming\Code\Cache\Cache_Data\data_3
0xcb0f58c70b60  \Users\User\AppData\Roaming\Code\Cache\Cache_Data\data_3
0xcb0f5f437d40  \Users\User\AppData\Roaming\discord\Cache\Cache_Data\data_3
0xcb0f5f438510  \Users\User\AppData\Roaming\discord\Cache\Cache_Data\data_3
</code></pre></div></div>

<p>Errors on the dumping the files. but i think it got some stuff. the clue says they might be images so im going to try and open them up in gimp to see whats there. Im not really finding anything with GIMP. lots of just garbled images not really images at all to be honest. Maybe Im missing something. I did a blanket search for data_3 and think that There may be some other data I can get from the GPUCache or the DawnCache. Do i know what those do? Nope. But they could be a lead.</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0xcb0f58c630a0  \Users\User\AppData\Roaming\Code\GPUCache\data_3
0xcb0f58c63550  \Users\User\AppData\Roaming\Code\GPUCache\data_3
0xcb0f58c657b0  \Users\User\AppData\Roaming\Code\DawnCache\data_3
0xcb0f58c66110  \Users\User\AppData\Roaming\Code\DawnCache\data_3
0xcb0f5f42b860  \Users\User\AppData\Roaming\discord\DawnCache\data_3
0xcb0f5f42bb80  \Users\User\AppData\Roaming\discord\DawnCache\data_3
0xcb0f5f42bd10  \Users\User\AppData\Roaming\discord\GPUCache\data_3
0xcb0f5f42bea0  \Users\User\AppData\Roaming\discord\DawnCache\data_2
0xcb0f5f42c4e0  \Users\User\AppData\Roaming\discord\GPUCache\data_3

</code></pre></div></div>

<p>Hmmm even less data for the GPUCache and DawnCache. Screw that…</p>

<p>After creating my own forensic machines and getting the updated tools this was a lot easier to process.</p>

<p>Using binwalk on the data_3 files, i extracted SSL certs from the code source. Maybe that will come about later. The Discord one had a TIFF image and PNG image. The TIFF image I couldnt open possibly corrupted? Or maybe its the one that is encrypted. Not sure but will come back to it.</p>

<p>Extracting the png image yields this image:
![[Pasted image 20250614200956.png]]
I pasted a screengrab of this into google image search and they are semaphore flag signals apparently so I looked into them. Using the schematic here: https://upload.wikimedia.org/wikipedia/commons/0/0a/Semaphore_Signals_A-Z.jpg we get the message:
<code class="language-plaintext highlighter-rouge">JCNNQ</code>
Hmmm no signal for the next letter but there is one for the reverse of the signal? maybe ill flip the images?
<code class="language-plaintext highlighter-rouge">PENNYWORTH</code> 
Ahh yes that seems more likely. From my batman knowledge pennyworth is the last name of Batmans butler Alfred.</p>

<p>So now where? lets look at the clue again:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>"""
Deep within the gamer's lore
Is a secret waiting to be unlocked

Find the file that holds the cached key
Maybe what you are looking for is data_3
It might hold the images that you seek

Conversations notified but left unseen.
And within the quiet pings, where alerts softly chime,
Another piece awaits, revealing the r1ddl3r's crime.
""" 
</code></pre></div></div>
<p>Ok first 2 sentences are just lead in I think, The file with the cached key, so the vscode file had a bunch of keys so I think i got that? the second it says images, plural? so maybe the TIFF file needs to be looked at again.</p>

<p>So yeah lots of binwalking these files. binwalking the PNG shows another tiff file. The tiff is actually supposed to be a WEBP possibly? not sure but looking at the file in XXD I see this encoded string. Its about discord and mentions a url</p>

<pre><code class="language-hex">00005210: 0000 3010 0000 036d 470a 1352 a09c a377  ..0....mG..R...w
00005220: 2f00 b12b a69c a377 2f00 2e03 0000 4854  /..+...w/.....HT
00005230: 5450 2f31 2e31 2032 3030 0064 6174 653a  TP/1.1 200.date:
00005240: 5765 642c 2032 3220 4d61 7920 3230 3234  Wed, 22 May 2024
00005250: 2031 363a 3231 3a33 3920 474d 5400 636f   16:21:39 GMT.co
00005260: 6e74 656e 742d 7479 7065 3a69 6d61 6765  ntent-type:image
00005270: 2f77 6562 7000 636f 6e74 656e 742d 6c65  /webp.content-le
00005280: 6e67 7468 3a35 3734 3200 6366 2d72 6179  ngth:5742.cf-ray
00005290: 3a38 3837 6532 3366 3461 6533 6638 3030  :887e23f4ae3f800
000052a0: 342d 4d41 4100 6366 2d63 6163 6865 2d73  4-MAA.cf-cache-s
000052b0: 7461 7475 733a 4d49 5353 0061 6363 6570  tatus:MISS.accep
000052c0: 742d 7261 6e67 6573 3a62 7974 6573 2c20  t-ranges:bytes, 
000052d0: 6279 7465 7300 6163 6365 7373 2d63 6f6e  bytes.access-con
000052e0: 7472 6f6c 2d61 6c6c 6f77 2d6f 7269 6769  trol-allow-origi
000052f0: 6e3a 2a00 6361 6368 652d 636f 6e74 726f  n:*.cache-contro
00005300: 6c3a 7075 626c 6963 2c20 6d61 782d 6167  l:public, max-ag
00005310: 653d 3331 3533 3630 3030 0065 7870 6972  e=31536000.expir
00005320: 6573 3a54 6875 2c20 3232 204d 6179 2032  es:Thu, 22 May 2
00005330: 3032 3520 3136 3a32 313a 3339 2047 4d54  025 16:21:39 GMT
00005340: 006c 6173 742d 6d6f 6469 6669 6564 3a57  .last-modified:W
00005350: 6564 2c20 3232 204d 6179 2032 3032 3420  ed, 22 May 2024 
00005360: 3136 3a32 313a 3338 2047 4d54 0076 6172  16:21:38 GMT.var
00005370: 793a 4163 6365 7074 2d45 6e63 6f64 696e  y:Accept-Encodin
00005380: 6700 782d 6469 7363 6f72 642d 7472 616e  g.x-discord-tran
00005390: 7366 6f72 6d2d 6475 7261 7469 6f6e 3a31  sform-duration:1
000053a0: 3500 7265 706f 7274 2d74 6f3a 7b22 656e  5.report-to:{"en
000053b0: 6470 6f69 6e74 7322 3a5b 7b22 7572 6c22  dpoints":[{"url"
000053c0: 3a22 6874 7470 733a 5c2f 5c2f 612e 6e65  :"https:\/\/a.ne
000053d0: 6c2e 636c 6f75 6466 6c61 7265 2e63 6f6d  l.cloudflare.com
000053e0: 5c2f 7265 706f 7274 5c2f 7634 3f73 3d53  \/report\/v4?s=S
000053f0: 425a 6153 4b73 2532 4644 367a 3061 7154  BZaSKs%2FD6z0aqT
00005400: 305a 4c65 5768 7966 4b6d 6f37 6d43 7a69  0ZLeWhyfKmo7mCzi
00005410: 5443 7659 6c7a 4965 6d45 6b6b 4b61 496f  TCvYlzIemEkkKaIo
00005420: 4a38 6148 4b79 344c 4641 3255 6a69 6264  J8aHKy4LFA2Ujibd
00005430: 7874 7749 5746 6c59 2532 4241 466c 7267  xtwIWFlY%2BAFlrg
00005440: 7241 5673 734d 7070 5267 6645 7043 6547  rAVssMppRgfEpCeG
00005450: 4831 517a 4b59 6e62 6561 6135 4833 2532  H1QzKYnbeaa5H3%2
00005460: 4254 4f55 646f 6563 7130 4a62 544b 615a  BTOUdoecq0JbTKaZ
00005470: 7a68 696e 4c59 6245 756d 6f53 5622 7d5d  zhinLYbEumoSV"}]
00005480: 2c22 6772 6f75 7022 3a22 6366 2d6e 656c  ,"group":"cf-nel
00005490: 222c 226d 6178 5f61 6765 223a 3630 3438  ","max_age":6048
000054a0: 3030 7d00 6e65 6c3a 7b22 7375 6363 6573  00}.nel:{"succes
000054b0: 735f 6672 6163 7469 6f6e 223a 302c 2272  s_fraction":0,"r
000054c0: 6570 6f72 745f 746f 223a 2263 662d 6e65  eport_to":"cf-ne
000054d0: 6c22 2c22 6d61 785f 6167 6522 3a36 3034  l","max_age":604
000054e0: 3830 307d 0078 2d72 6f62 6f74 732d 7461  800}.x-robots-ta
000054f0: 673a 6e6f 696e 6465 782c 206e 6f66 6f6c  g:noindex, nofol
00005500: 6c6f 772c 206e 6f61 7263 6869 7665 2c20  low, noarchive, 
00005510: 6e6f 6361 6368 652c 206e 6f69 6d61 6765  nocache, noimage
00005520: 696e 6465 782c 206e 6f6f 6470 0073 6572  index, noodp.ser
00005530: 7665 723a 636c 6f75 6466 6c61 7265 0061  ver:cloudflare.a
00005540: 6c74 2d73 7663 3a68 333d 223a 3434 3322  lt-svc:h3=":443"
00005550: 3b20 6d61 3d38 3634 3030 0000 0000 0300  ; ma=86400......

</code></pre>
<p>{“url”:”https:\/\/a.nel.cloudflare.com\/report\/v4s=SBZaSKs%2FD6z0aqT0ZLeWhyfKmo7mCziTCvYlzIemEkkKaIoJ8aHKy4LFA2UjibdxtwIWFlY%2BAFlrgrAVssMppRgfEpCeGH1QzKYnbeaa5H3%2BTOUdoecq0JbTKaZzhinLYbEumoSV</p>

<p>Looks base encoded with some url encoding as well. Possibly a discord token since it looks like an API request. I tried navigating there but nothing to report.</p>

<p>So the hint talks about notifications unseen so I think there is some way to find discord messages?</p>

<p>Online i found some reference to cache data again so I’m going to try that:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0xcb0f5f439c80	\Users\User\AppData\Roaming\discord\Cache\Cache_Data\data_0
0xcb0f5f439e10	\Users\User\AppData\Roaming\discord\Cache\Cache_Data\data_1
0xcb0f5f43a130	\Users\User\AppData\Roaming\discord\Cache\Cache_Data\data_2
</code></pre></div></div>
<p>So i found some images in data_2 but they are all just discord asset images. 
data_1 had a gzip compressed file and uncompressing it shows a list of regions and ips:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[{"region":"india","ips":["35.207.240.251","66.22.239.5","35.207.210.191","35.207.211.253","35.207.224.151"]},{"region":"dubai","ips":["66.22.242.8","66.22.242.133","66.22.242.137","66.22.242.6","66.22.242.10"]},{"region":"singapore","ips":["66.22.220.14","35.213.168.191","35.213.165.33","35.213.167.165","35.213.145.149"]},{"region":"hongkong","ips":["35.215.190.51","35.215.161.122","35.215.128.17","35.215.172.57","35.215.149.186"]},{"region":"tel-aviv","ips":["34.0.64.32","34.0.64.225","34.0.64.50","34.0.65.227","34.0.65.31"]}]
</code></pre></div></div>
<p>I doubt this is significant and could possibly be related to some type of CDN type stuff but the locations are pretty suspicious to say the least.</p>

<p>So I was kind of in a stump so I asked for a hint. I knew it had to do with notifications. So i grepped filescan for notifi to see what was there:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>vol3 -f trinity.raw windows.filescan | grep notifi
0xcb0f5de9a540.0\Users\User\AppData\Local\Discord\app-1.0.9147\modules\discord_utils-1\discord_utils\node_modules\macos-notification-state\build\Release\notificationstate.node
0xcb0f5e1aad90	\Windows\System32\notificationplatformcomponent.dll
0xcb0f5f0042b0	\Users\User\AppData\Local\Discord\app-1.0.9147\modules\discord_utils-1\discord_utils\node_modules\windows-notification-state\build\Release\notificationstate.node
0xcb0f5f43bbc0	\Users\User\AppData\Local\Discord\app-1.0.9147\modules\discord_utils-1\discord_utils\node_modules\macos-notification-state\package.json
0xcb0f5f43f8b0	\Users\User\AppData\Local\Discord\app-1.0.9147\modules\discord_utils-1\discord_utils\node_modules\macos-notification-state\lib\index.js
0xcb0f5f43fef0	\Users\User\AppData\Local\Discord\app-1.0.9147\modules\discord_utils-1\discord_utils\node_modules\windows-notification-state\package.json
0xcb0f5f441660	\Users\User\AppData\Local\Discord\app-1.0.9147\modules\discord_utils-1\discord_utils\node_modules\windows-notification-state\lib\index.js
</code></pre></div></div>
<p>It came back with this which i dont know if its helpful but worth a look</p>

<p>Looking for notifications in general, discord and other programs occassionally have notifications storedin the NTUSER.dat registry so diving into that registry i see under SOFTWARE/Microsoft/Windows/Current Version/Notifications/ some interesting keys that could lead to some clues. Nope. Not even. Close.</p>

<p>After struggling on this for a bit, I reached out to an admin to get some hints on where else I could look. Apparently there is a db called wpndatabase.db that you can dump and analyze so I did windows.filescan and greped for that db and found the virtual address and dumped the file. Now to analyze it. Using SQLITE DB Browser and navigating the Notification table, I found an encrypted string: <code class="language-plaintext highlighter-rouge">Y2lwaGVydGV4dCA9ICI6MD07J1x4MTFoLyhvLlx4MGJoJTJvXHgwM1x4MGI0M1x4MTUvXHgwODQ5XHgwOC4pb1x4MTFoLyhvLjFtMjhceDAzXHgwZW04ODBvXHgxMW9ceDA4NGgoISIK</code></p>

<p>So lets use the password PENNYWORTH and the this cipher text and use the vb script to decrypt it. It doesnt really look like an encrypted string. Lets see if its base64 encoded…Yep! It decodes to: 
<code class="language-plaintext highlighter-rouge">ciphertext = ":0=;'\x11h/(o.\x0bh%2o\x03\x0b43\x15/\x0849\x08.)o\x11h/(o.1m28\x03\x0em880o\x11o\x084h(!"</code>
So our cipher text is actually <code class="language-plaintext highlighter-rouge">:0=;'\x11h/(o.\x0bh%2o\x03\x0b43\x15/\x0849\x08.)o\x11h/(o.1m28\x03\x0em880o\x11o\x084h(!</code></p>

<p>The VBS script does not really work as its missing some components so lets convert it to python for some easier decrypting. I used Claude AI to look at the vbs code and generate this script. Basically though, the vbs script does some XOR encryption 10x. So the following is the script that I used to decipher the string:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">hashlib</span>

<span class="k">def</span> <span class="nf">decrypt</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">password</span><span class="p">):</span>
<span class="err"> </span> <span class="err"> </span> <span class="n">key</span> <span class="o">=</span> <span class="n">hash_password</span><span class="p">(</span><span class="n">password</span><span class="p">)</span>
<span class="err"> </span> <span class="err"> </span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">11</span><span class="p">):</span>
<span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="n">encrypted_message</span> <span class="o">=</span> <span class="s">""</span>
<span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">message</span><span class="p">)):</span>
<span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="n">char</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="n">j</span><span class="p">]</span>
<span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="n">key_char</span> <span class="o">=</span> <span class="n">key</span><span class="p">[(</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="n">key</span><span class="p">)]</span>
<span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="n">decrypted_char</span> <span class="o">=</span> <span class="nb">chr</span><span class="p">(</span><span class="nb">ord</span><span class="p">(</span><span class="n">char</span><span class="p">)</span> <span class="o">^</span> <span class="nb">ord</span><span class="p">(</span><span class="n">key_char</span><span class="p">))</span>
<span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="n">encrypted_message</span> <span class="o">+=</span> <span class="n">decrypted_char</span>
<span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="n">message</span> <span class="o">=</span> <span class="n">encrypted_message</span>
<span class="err"> </span> <span class="err"> </span> <span class="k">return</span> <span class="n">encrypted_message</span>

<span class="k">def</span> <span class="nf">hash_password</span><span class="p">(</span><span class="n">text</span><span class="p">):</span>
<span class="err"> </span> <span class="err"> </span> <span class="n">sha256_hash</span> <span class="o">=</span> <span class="n">hashlib</span><span class="p">.</span><span class="n">sha256</span><span class="p">(</span><span class="n">text</span><span class="p">.</span><span class="n">encode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">)).</span><span class="n">hexdigest</span><span class="p">()</span>
<span class="err"> </span> <span class="err"> </span> <span class="k">return</span> <span class="n">sha256_hash</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
<span class="err"> </span> <span class="err"> </span> <span class="n">password</span> <span class="o">=</span> <span class="s">"PENNYWORTH"</span>
<span class="err"> </span> <span class="err"> </span> <span class="n">ciphertext</span> <span class="o">=</span> <span class="s">":0=;'</span><span class="se">\x11</span><span class="s">h/(o.</span><span class="se">\x0b</span><span class="s">h%2o</span><span class="se">\x03\x0b</span><span class="s">43</span><span class="se">\x15</span><span class="s">/</span><span class="se">\x08</span><span class="s">49</span><span class="se">\x08</span><span class="s">.)o</span><span class="se">\x11</span><span class="s">h/(o.1m28</span><span class="se">\x03\x0e</span><span class="s">m880o</span><span class="se">\x11</span><span class="s">o</span><span class="se">\x08</span><span class="s">4h(!"</span>
<span class="err"> </span> <span class="err"> </span> <span class="n">decrypted</span> <span class="o">=</span> <span class="n">decrypt</span><span class="p">(</span><span class="n">ciphertext</span><span class="p">,</span> <span class="n">password</span><span class="p">)</span>
<span class="err"> </span> <span class="err"> </span> <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Decrypted: </span><span class="si">{</span><span class="n">decrypted</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
</code></pre></div></div>

<p>Running the script we get:
Decrypted: <code class="language-plaintext highlighter-rouge">flag{M4st3rW4yn3_WhoIsTheTru3M4st3rm1nd_R1ddl3M3Th4t}</code></p>]]></content><author><name>Benshkies</name></author><category term="dfir" /><category term="ctf-dfirlabs" /><summary type="html"><![CDATA[(Image generated by ChatGPT) Unzipping the file shows another raw file, so lets search for a profile in volatility $ vol.py -f DFIRLABS.raw imageinfo Volatility Foundation Volatility Framework 2.6.1 INFO : volatility.debug : Determining profile based on KDBG search... Suggested Profile(s) : Win10x64_19041 AS Layer1 : SkipDuplicatesAMD64PagedMemory (Kernel AS) AS Layer2 : FileAddressSpace (/home/sansforensics/DFIRLABS.raw) PAE type : No PAE DTB : 0x1aa000L KDBG : 0xf80681a00b20L Number of Processors : 4 Image Type (Service Pack) : 0 KPCR for CPU 0 : 0xfffff8067dee2000L KPCR for CPU 1 : 0xffffa2814c5a0000L KPCR for CPU 2 : 0xffffa2814bfa1000L KPCR for CPU 3 : 0xffffa2814c30e000L KUSER_SHARED_DATA : 0xfffff78000000000L Image date and time : 2024-05-22 16:22:06 UTC+0000 Image local date and time : 2024-05-22 21:52:06 +0530 Looks like our image profile will be Win10x64_19041]]></summary></entry><entry><title type="html">DFIRLABS: Gotham Hustle</title><link href="/2025/06/01/dfir-labs-gotham-hustle.html" rel="alternate" type="text/html" title="DFIRLABS: Gotham Hustle" /><published>2025-06-01T23:41:34+00:00</published><updated>2025-06-01T23:41:34+00:00</updated><id>/2025/06/01/dfir-labs-gotham-hustle</id><content type="html" xml:base="/2025/06/01/dfir-labs-gotham-hustle.html"><![CDATA[<p><img src="/assets/images/chatgpt-batman-hustle.png" alt="ChatGPT Gotham Hustle" /> <em>(Image generated by ChatGPT)</em></p>

<h2 id="the-beginning-to-suffering">The Beginning to Suffering</h2>
<p>Volatility has always been one of those tools that was, like, cool, but I never saw true utility out of it other than running basic modules and having the output for the flag given to me. This challenge is definitely not that. It makes you sweat and bleed for the flags. So in the spirit of that, I will give you a rundown of my hardships while learning the ins and outs of basic Volatility.</p>

<h2 id="the-suffering">The Suffering</h2>

<p>First things first, let’s get the basic image information so we know what we are dealing with:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">python3</span><span class="w"> </span><span class="nx">vol.py</span><span class="w"> </span><span class="nt">-f</span><span class="w"> </span><span class="s2">"C:\Users\benshkies\Desktop\Cases\gotham\gotham.raw"</span><span class="w"> </span><span class="nx">windows.info.Info</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ForEach-Object</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="bp">$_</span><span class="o">.</span><span class="nf">Trim</span><span class="p">()</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Set-Content</span><span class="w"> </span><span class="s2">"</span><span class="nv">$output_dir</span><span class="s2">\mem_info.txt"</span><span class="w">
</span></code></pre></div></div>

<p>By default, Volatility’s output is kind of wack, so I used some PowerShell to trim up the white space.
For the rest of the plugins, I’ll use this line and then just set the plugin before I run it. That way, output is consistent:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># set $plugin = "&lt;plugin name&gt;"</span><span class="w">
</span><span class="n">python3</span><span class="w"> </span><span class="nx">vol.py</span><span class="w"> </span><span class="nt">-f</span><span class="w"> </span><span class="s2">"C:\Users\benshkies\Desktop\Cases\gotham\gotham.raw"</span><span class="w"> </span><span class="nv">$plugin</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ForEach-Object</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="bp">$_</span><span class="o">.</span><span class="nf">Trim</span><span class="p">()</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Set-Content</span><span class="w"> </span><span class="s2">"</span><span class="nv">$output_dir</span><span class="s2">\</span><span class="nv">$plugin</span><span class="s2">.txt"</span><span class="w">
</span></code></pre></div></div>

<p>Nothing catches my eye with the output of <code class="language-plaintext highlighter-rouge">pslist</code>.
Moving on to the Envars (plugin: <code class="language-plaintext highlighter-rouge">windows.envars.Envars</code>):</p>

<ul>
  <li>Computername: Bruce-PC</li>
  <li>USERNAME	bruce</li>
  <li>USERPROFILE	C:\Users\bruce
Not seeing anything else here. Lots of repeating data about a <code class="language-plaintext highlighter-rouge">csilogfile.log</code>, but don’t think that’s anything.</li>
</ul>

<p>Not shown here is me trying 13 other modules and finding zilch, nada, zero on anything at all. Then a well-placed question to the DFIRLABS Discord nets me:
“$I$ would suggest you to try Volatility 2 for this lab as it’s an older version of Windows and it’s only the challenge to give you experience on using Volatility.”</p>

<h2 id="the-suffering-but-with-vol2">The Suffering but with Vol2</h2>

<p>Volatility2 can be downloaded, but after spending an hour trying to get Python2 installed on my Win11 VM and it failing to read my env variables and install Python2 correctly, I downloaded the SANS SIFT workstation image and did that instead because it has Vol2 included along with all the community modules. SCORE!</p>

<p>So a quick boot of that VM and we are off with Vol2.</p>

<p>Volatility2 is specific in that it needs a specific profile to run the modules on. To do that, we use the <code class="language-plaintext highlighter-rouge">imageinfo</code> module:
<code class="language-plaintext highlighter-rouge">vol.py -f gotham.raw imageinfo</code></p>

<p>Then we get output somewhat like:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Suggested Profile(s) : Win7SP1x64, Win7SP0x64, Win2008R2SP0x64, Win2008R2SP1x64_24000, Win2008R2SP1x64_23418, Win2008R2SP1x64, Win7SP1x64_24000, Win7SP1x64_23418
</code></pre></div></div>

<p>Since <code class="language-plaintext highlighter-rouge">Win7SP1x64_23418</code> is the latest version, I’ll just stick with that.</p>

<p>Now let’s try some basic commands:
<code class="language-plaintext highlighter-rouge">vol.py -f gotham.raw --profile Win7SP1x64_23418 psscan</code> — Yields… nothing… great.</p>

<p>When in doubt, run strings. Let’s get a string dump of the image and see if we can get some easy wins:
<code class="language-plaintext highlighter-rouge">strings gotham.raw &gt;&gt; strings.txt</code>
Now we’ll use the strings command for some analysis with <code class="language-plaintext highlighter-rouge">grep</code>. Is this necessary? Idk, but I did it.</p>

<p><code class="language-plaintext highlighter-rouge">vol.py -f gotham.raw --profile Win7SP1x64_23418 strings -s strings.txt | grep gotham</code>
This outputs a peculiar set of strings</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Volatility Foundation Volatility Framework 2.6.1
744406256 [FREE MEMORY:-1] &lt;h2 id="Challenge-Description"&gt;&lt;a href="#Challenge-Description" class="headerlink" title="Challenge Description:"&gt;&lt;/a&gt;Challenge Description:&lt;/h2&gt;&lt;p&gt;Bruce Wayne was alerted that Joker have escaped from Arkham Asylum, Joker with all the Gotham outlaws crafts a letter for Bruce, He wants to make it go all crazy x_0!,and now Batman gets a message sent to Him with a letter, but apparently as Damain was in the Desktop, he opens it and everything goes crazy, the letter is now distributed to everyone in gotham, if Batman doesn
1085961673 [FREE MEMORY:-1] Jgotham
1098571519 [FREE MEMORY:-1] gotham-chess.com/
</code></pre></div></div>

<p>BUT the above is actually a clue to Batman 4, so not very helpful.</p>

<p>BUT below, using another basic command, <code class="language-plaintext highlighter-rouge">cmdscan</code>, we can see a command history of our boi Brucey Wayne:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ vol.py -f gotham.raw --profile Win7SP1x64_23418 cmdscan
...
Cmd #4 @ 0x12d690: Ymkwc2N0Znt3M2xjMG0zXw==
Cmd #5 @ 0x12d6d0: azr43ln1ght.github.io
...
</code></pre></div></div>

<p>Is that a flag I see? Yes! Is that also <a href="https://azr43ln1ght.github.io">Azr43lKn1ght</a> doing some self-promotion in a challenge?
Up for debate. Nonetheless, decoding the base64 string gives us:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">echo</span> <span class="s2">"Ymkwc2N0Znt3M2xjMG0zXw=="</span> | <span class="nb">base64</span> <span class="nt">-d</span>
bi0sctf<span class="o">{</span>w3lc0m3_
</code></pre></div></div>

<p><img src="/assets/images/office-no.gif" alt="" />
So the flag is in parts, so we are in for a ride with this challenge.</p>

<p>I saw some activity on Bruce’s desktop, so I did the <code class="language-plaintext highlighter-rouge">filescan</code> command with a <code class="language-plaintext highlighter-rouge">grep</code> pipe to look for files specifically in that directory because <code class="language-plaintext highlighter-rouge">filescan</code> is a beast to parse through without any grep.
The <code class="language-plaintext highlighter-rouge">-F</code> means to take the string as a string and not a regular expression.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>vol.py <span class="nt">-f</span> gotham.raw <span class="nt">--profile</span><span class="o">=</span>Win7SP1x64_23418 filescan | <span class="nb">grep</span> <span class="nt">-F</span> <span class="s2">"bruce</span><span class="se">\D</span><span class="s2">esktop"</span>
</code></pre></div></div>

<p>Flag5.rar seems promising. Let’s see if we can extract it:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>vol.py <span class="nt">-f</span> gotham.raw <span class="nt">--profile</span><span class="o">=</span>Win7SP1x64_23418 dumpfiles <span class="nt">--dump-dir</span><span class="o">=</span>output/ <span class="nt">-Q</span> 0x000000011fdaff20 
</code></pre></div></div>

<p>Getting that downloaded and running <code class="language-plaintext highlighter-rouge">strings</code> outputs:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
The password for the zip file is the computer's password...
</code></pre></div></div>

<p>Just to see real quick if we could get Bruce’s password, I used the <code class="language-plaintext highlighter-rouge">hashdump</code> module to dump the NTLM hashes.
Bruce’s password gets cracked into <code class="language-plaintext highlighter-rouge">batman</code> using crackstation.net.
Using that password on the zip file yields part 5 of the flag: <code class="language-plaintext highlighter-rouge">m0r3_13337431}</code></p>

<p>So we got the first and last flags first… guess that means we are pretty elite… or that we are really bad at finding basic things.</p>

<p>On another note, I see a lot of Chrome processes and activity in the process list, but when I run the <code class="language-plaintext highlighter-rouge">chromehistory</code> plugin, there are no results.
It looks to be broken. (Did I know that it was broken for the 2 hours I spent trying to find artifacts from Chrome? I certainly did not!)
So after a gracious DFIRLABS admin clued me in that it should return stuff, I copied the <code class="language-plaintext highlighter-rouge">chromehistory.py</code> file <a href="https://github.com/superponible/volatility-plugins/blob/master/chromehistory.py">here</a> and pasted it over the code in the plugins/community directory and now it works and shows me the Chrome history.</p>

<p>First line shows this:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flag3 = aDBwM190aDE1Xw==
</code></pre></div></div>

<p>Another flag I see. Base64 decode it and it shall be: <code class="language-plaintext highlighter-rouge">h0p3_th15_</code></p>

<p>Ok, so now we got 1, 3, 5. Only 2 to go.
The whole flag so far is:</p>

<p><code class="language-plaintext highlighter-rouge">bi0sctf{w3lc0m3_{FLAG2}h0p3_th15_{FLAG4}m0r3_13337431}</code></p>

<p>Let’s try seeing what the Paint and Notepad processes were up to.
From <code class="language-plaintext highlighter-rouge">pslist</code>, I got the following:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>notepad.exe            2592 
mspaint.exe            2516  
</code></pre></div></div>

<p>Let’s try dumping those processes:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>volatility <span class="nt">-f</span> test.raw <span class="nt">--profile</span><span class="o">=</span>Win7SP1x86_23418 memdump <span class="nt">--dump-dir</span><span class="o">=</span>./ <span class="nt">-p</span> 2592
</code></pre></div></div>

<p>Running <code class="language-plaintext highlighter-rouge">strings</code> on the Notepad data, I was able to find flag 4.
LOL is that flag 3? So if I was smart, I could have found both… great…</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flag4 <span class="o">=</span> <span class="nv">YjNuM2YxNzVfeTB1Xw</span><span class="o">==</span>
</code></pre></div></div>

<p>Is it cheeky to grep for flag? Maybe… but you get desperate when you’ve spent the last 2 hours searching the interwebs on how to parse a Notepad file with Volatility only to find out that you forgot the already quoted quote: “When in doubt, run strings” and could have found it much much earlier.</p>

<p>Flag4 decodes to: <code class="language-plaintext highlighter-rouge">b3n3f175_y0u_</code></p>

<p>Doing the same for MSPaint doesn’t yield any results for flag two. OR does it? Turns out you gotta be simp and use GIMP to have any success here.
This involved a lot of fiddling—oh, did I mention that scrolling to the bottom of the image when changing the options helps a bunch?
I had to do a lot of fiddling with this to find the correct layout.
Micro adjustments will make your life a lot easier as you transform the image. In the end, I used RGB 16-bit and tried a bunch of offsets and finally found some text at the bottom.
Once you have the image set in place, you can flip it 180 and horizontal to reveal an image of a base64-encoded value:
<code class="language-plaintext highlighter-rouge">dDBfZGYxcl9sNGl1Xw==</code></p>

<p>Can you tell what is a capital “I” and what is an “l”? Well, you better start guessing and mixing and matching to find out!
Ah, I just love ambiguous fonts.</p>

<p>Finally, decoding this last value and putting it in its place yields:</p>

<p><code class="language-plaintext highlighter-rouge">bi0sctf{w3lc0m3_t0_df1r_l4b5_h0p3_th15_b3n3f175_y0u_m0r3_13337431}</code></p>

<h2 id="reflections-on-suffering">Reflections on Suffering</h2>

<p>This challenge was very well written. It gives a broad introduction into Volatility and presents you with unique situations that require some Volatility documentation digging to get the flags. When the challenge says “Easy,” it does not mean easy for <em>anyone</em>. It means easy for those already acquainted with Volatility and memory forensics. This gave me a new appreciation for the tool and showed me just how much I had been missing. There is still so much that I don’t know, but I hope to learn more about the tool as I continue learning in DFIR. Thanks to <a href="https://github.com/Azr43lKn1ght/DFIR-LABS/tree/main">DFIRLABS</a> for putting this challenge together! Next up is <em>Trinity of Secrets</em>.</p>]]></content><author><name>Benshkies</name></author><category term="dfir" /><category term="ctf-dfirlabs" /><summary type="html"><![CDATA[(Image generated by ChatGPT)]]></summary></entry></feed>