<?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[Alireza's Blog]]></title><description><![CDATA[Write-ups on hacking into systems and breaking things to learn how they work - from a security researcher's perspective.]]></description><link>https://kalhor.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6915c7f949601a992bf84ff8/a0c8d937-85df-4603-bad3-0648c201cf5e.png</url><title>Alireza&apos;s Blog</title><link>https://kalhor.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Mon, 31 Aug 2026 19:49:35 GMT</lastBuildDate><atom:link href="https://kalhor.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[CVE-2026-17532: nonce: true => Web Shell]]></title><description><![CDATA[Unauthenticated reflected XSS to 1-click RCE in Seraphinite Accelerator, a WordPress caching plugin on 50,000+ sites.

The site that looked clean
What would you do if I told you that just by opening y]]></description><link>https://kalhor.hashnode.dev/cve-2026-17532-nonce-true-web-shell</link><guid isPermaLink="true">https://kalhor.hashnode.dev/cve-2026-17532-nonce-true-web-shell</guid><category><![CDATA[CVE-2026-17532]]></category><category><![CDATA[wordpress security ]]></category><category><![CDATA[Seraphinite Accelerator]]></category><category><![CDATA[#Reflected-XSS]]></category><category><![CDATA[Remote Code Execution]]></category><category><![CDATA[Authentication Bypass]]></category><category><![CDATA[PHP Type Juggling]]></category><category><![CDATA[vulnerability research]]></category><dc:creator><![CDATA[Alireza Kalhor]]></dc:creator><pubDate>Tue, 25 Aug 2026 14:17:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/743dfeee-6d1f-4a5c-a520-90f5a1e9880a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Unauthenticated reflected XSS to 1-click RCE in Seraphinite Accelerator, a WordPress caching plugin on 50,000+ sites.</strong></p>
<hr />
<h2>The site that looked clean</h2>
<p>What would you do if I told you that just by opening your own WordPress site, your whole server could get hacked?</p>
<p>That's the short version of CVE-2026-17532.</p>
<p>A few weeks ago a client hired me to test their WordPress site. I started with the usual checks - the ones that normally give me an easy way in. No exposed <code>xmlrpc.php</code>. No outdated plugin. Nothing misconfigured. The site was clean and fully patched.</p>
<p>So I changed my plan. Instead of looking for a mistake in how the site was set up, I went after the code of a plugin it used: <strong>Seraphinite Accelerator</strong>.</p>
<h2>Why a caching plugin</h2>
<p>I didn't have a strategy here - this was just the first plugin I checked out of everything installed on the site. No special reasoning going in.</p>
<p>Seraphinite Accelerator is a caching plugin, active on more than 50,000 sites, rated 4.8 out of 5 stars. It's exactly the kind of plugin nobody looks at twice - popular, well reviewed, "just" a cache.</p>
<p>Turns out that's exactly what makes it interesting. A caching plugin has to run <em>early</em>, before WordPress finishes loading, so it can serve pages fast. Code that runs that early has almost none of WordPress's usual protection around it yet. Looking back, that's what made it worth the extra look - I just got lucky picking it first.</p>
<p>I downloaded the free version from wordpress.org, unpacked it, and handed it to my agent.</p>
<h2>Agent47</h2>
<p>I have an agent I built for exactly this kind of work - I call it Agent47. Its only goal is to find real, exploitable High/Critical bugs in source code - not lint warnings, not "this could maybe be an issue somewhere."</p>
<p>It works in two phases, each starting from a clean memory so it never gets lost in its own notes:</p>
<ul>
<li><p><strong>Phase 1 - map the surface.</strong> Walk every entry point, every parameter, every place user input touches something dangerous, and rank what's worth a closer look.</p>
</li>
<li><p><strong>Phase 2 - hunt.</strong> Take one lead at a time, from a clean context, and chase it until it's dead or it's a working exploit.</p>
</li>
</ul>
<p>That split is why it didn't stop at the first bug. Most scanners would flag the loose <code>!=</code> and call it a day - a nice-to-fix, low severity. Agent47 kept going: once it was past the check, it kept asking what that access was actually good for. That's how one auth bypass turned into two independent bugs, chained.</p>
<h2>Bug #1 - the check that never checks</h2>
<p>The plugin has an internal "prepare page" feature that builds its cache. To make sure only the plugin can call it, every request needs a signed token in the <code>seraph_accel_prep</code> parameter - base64 JSON with a <code>nonce</code> field, an HMAC signed with the site's own secret. An attacker shouldn't be able to forge it.</p>
<p>Here's the check, from version 2.29.15:</p>
<pre><code class="language-php">// common.php, CacheExtractPreparePageParams()
if( hash_hmac( 'md5', '' . ($prms['_tm'] ?? null), GetSalt() ) != ($prms['nonce'] ?? null) )
    return( false );
</code></pre>
<p>Read it out loud: "work out the real signature, and if it doesn't match what the attacker sent, stop." Sounds fine. The problem is one character: <code>!=</code>. In PHP, that's a loose comparison.</p>
<p><code>hash_hmac()</code> always returns a real, non-empty string. And PHP has a rule for loose comparison: if one side is a boolean, the other side gets turned into a boolean too, before they're compared. Not the text - a boolean.</p>
<p>So instead of sending a fake signature, send the JSON boolean <code>true</code>:</p>
<pre><code class="language-php">hash_hmac(...)         !=  true
(bool) hash_hmac(...)  !=  true    // any non-empty string -&gt; true
true                   !=  true    // -&gt; false
</code></pre>
<p>The check returns false, meaning "don't stop" - the function carries on as if the signature was correct. PHP never actually reads a single character of the real HMAC. No secret needed, no guessing. Just the word <code>true</code> where a signature was supposed to go.</p>
<p>The fix, in version 2.29.19, is one character: <code>!=</code> becomes <code>!==</code>. A strict compare checks type and value both, so a boolean can never pretend to be a matching hash.</p>
<h2>Bug #2 - whatever you send becomes the page</h2>
<p>An auth bypass is only as good as what's behind it. And behind this one is a field called <code>selfTest</code>, in that same JSON. Once the fake signature gets past the check, this runs:</p>
<pre><code class="language-php">// cache_ex.php, _CbContentFinishSkip()
$content = 'selfTest-' . $seraph_accel_g_prepPrms['selfTest'];
</code></pre>
<p>That line throws away the real page and replaces the whole response with <code>selfTest-</code> plus whatever we put in <code>selfTest</code>. No escaping. Put <code>&lt;script&gt;alert(origin)&lt;/script&gt;</code> in there, and that's what the browser gets back - as the entire page.</p>
<p>This also doesn't run inside a normal WordPress request. Once page caching is turned on - the plugin's main feature - it installs a special file called <code>advanced-cache.php</code>, and WordPress loads that <em>before it finishes booting</em>. Plugins haven't loaded yet. The login system doesn't exist yet. There's nothing standing between our payload and the browser.</p>
<p>The fix wraps <code>selfTest</code> in a sanitizer that strips it down to a plain identifier. One function call would have stopped all of this.</p>
<h2>Turning it into a shell</h2>
<p>An XSS on its own runs JavaScript in someone's browser. Annoying, not much more. The reason this one is dangerous is who we point it at: a logged-in WordPress <strong>administrator</strong>, on their own site.</p>
<p>One link does it:</p>
<pre><code class="language-plaintext">http://SITE/?seraph_accel_prep=&lt;base64-json&gt;
</code></pre>
<p>where the JSON is:</p>
<pre><code class="language-json">{ "nonce": true, "selfTest": "&lt;script&gt;...&lt;/script&gt;" }
</code></pre>
<p><code>nonce: true</code> walks past Bug #1. <code>selfTest</code> becomes the whole page, unescaped, because of Bug #2. The moment the admin opens the link, our script runs <em>inside their own site</em>, with their own cookies and session.</p>
<p>From there the script does something simple: it uses the admin's session to open WordPress's built-in Plugin/Theme File Editor (on by default, and still on for most sites) and overwrite an inactive plugin file - <code>hello.php</code>, which ships with every WordPress install - with a small PHP web shell. It picks an inactive file on purpose: editing an <em>active</em> plugin that breaks the site gets auto-reverted by WordPress; an inactive one doesn't.</p>
<p>The whole chain, in one sentence: a crafted link -&gt; XSS before WordPress even finishes loading -&gt; the admin's own session writes a web shell through their own file editor -&gt; command execution on the server.</p>
<p>One link. One click. One shell.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/6901f69e-2043-41df-ac44-efccce1d4f7b.png" alt="The Exploit" style="display:block;margin:0 auto" />

<h2>Try it yourself</h2>
<p>I built a small Docker lab that runs the whole chain end to end, pinned to a vulnerable version.</p>
<pre><code class="language-bash">git clone https://github.com/kalhoralireza/CVE-2026-17532-lab.git &amp;&amp; cd CVE-2026-17532-lab
docker compose up -d
docker compose logs -f wpcli # wait for "LAB READY"
./exploit.sh
</code></pre>
<p>Log in at <code>/wp-admin</code>, open the crafted link the lab prints for you, and watch the console log the web shell URL. (It'll hang for a few seconds first - that's the plugin, not a broken lab.) That's the whole exploit.</p>
<h2>Fix it</h2>
<ul>
<li>Update to 2.29.19 or newer. That's the actual fix.</li>
</ul>
<h2>Why I'm telling you this</h2>
<p>This bug wasn't hidden. The loose <code>!=</code> sits right there in the source. So does the unescaped sink. Both sat in a plugin running on 50,000+ sites, and nobody looked, because "it's just a caching plugin."</p>
<p>That's the gap Agent47 is built for. I give it source code, it reads all of it - the boring parts too - and comes back with real, working exploits instead of a list of maybe-bugs. This one turned into a single URL that takes a fully patched WordPress site to a shell on the server.</p>
<p>If you've got code you'd bet is clean, I'd like to test that bet. Reach me at <a href="mailto:realalirezakalhor@gmail.com">my email</a> or on <a href="https://t.me/KalhorAlireza">Telegram</a>.</p>
<h2>Disclosure timeline</h2>
<ul>
<li><p><strong>Reported:</strong> 9th July, 2026</p>
</li>
<li><p><strong>Triaged:</strong> 27th July, 2026</p>
</li>
<li><p><strong>CVE assigned:</strong> 4th August, 2026</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Taking over a password-protected & FDE enabled OVF for fun and profit]]></title><description><![CDATA[Introduction
In the world of Linux system administration, resetting a password when access to the system has been restricted for one reason or another is a common challenge. The problem becomes especi]]></description><link>https://kalhor.hashnode.dev/taking-over-a-password-protected-fde-enabled-ovf-for-fun-and-profit</link><guid isPermaLink="true">https://kalhor.hashnode.dev/taking-over-a-password-protected-fde-enabled-ovf-for-fun-and-profit</guid><category><![CDATA[cucm]]></category><category><![CDATA[hack]]></category><category><![CDATA[grub]]></category><category><![CDATA[password recvery]]></category><category><![CDATA[Linux]]></category><category><![CDATA[cybersecurity]]></category><dc:creator><![CDATA[Alireza Kalhor]]></dc:creator><pubDate>Sat, 22 Aug 2026 15:57:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/adb4139d-367d-4b91-bca0-4e66a9644ffd.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>In the world of Linux system administration, resetting a password when access to the system has been restricted for one reason or another is a common challenge. The problem becomes especially critical when the usual password recovery methods — such as Rescue Mode or editing boot parameters — are themselves inaccessible because they require a password. Restrictions like these can lock administrators and users out of a system and make getting back in harder than ever.</p>
<p>In this post we take on that challenge and recover the password of a Linux system.</p>
<h2>1- Defining the Problem</h2>
<p>Imagine you are in charge of the IT department of a company and are responsible for administering and supporting several virtual servers. One of these servers, running a Linux system, is inaccessible because its password has been forgotten. This server handles important duties such as managing the company's databases or serving customers, and quick access to it is essential in order to prevent any disruption to the company's operations.</p>
<p>The problem, however, is that the common methods for resetting a Linux password — such as using rescue mode or editing the boot parameters — have been blocked for various reasons and require a password.</p>
<p>This scenario can happen to many IT professionals:</p>
<ul>
<li><p>The previous system administrator may have left the company without updating the security documentation.</p>
</li>
<li><p>After a system update or configuration changes, the system's access credentials may have been deleted or corrupted.</p>
</li>
</ul>
<p>In the next section we look at the common methods for recovering the password of a Linux system.</p>
<h2>2- Common Methods for Recovering the Password of a Linux System</h2>
<p>One of the common methods for recovering the password of a Linux operating system is to use the OS's Recovery mode. In this method we use Recovery mode to log in to the target system as the root user and change the password of the account we want. To demonstrate this method, we will use Ubuntu's Recovery Mode and start recovering our user's password.</p>
<p>In some cases, the booted operating system may not have an option such as Recovery/Rescue. For example, Cisco Unified Communications Manager — which from here on we will call CUCM — is an Appliance from Cisco, and Shell access to the system is not available by default. In this case we need an ISO of a Linux operating system so that we can solve our problem. Note that in the case of CUCM, the goal is to turn on SSH and enable the root user in order to gain access to the system. In what follows we explain the two methods mentioned.</p>
<h3>2.1- Recovering the Ubuntu Password Using Recovery Mode</h3>
<p>If your system fails to boot for any reason, it may be useful to boot it into recovery mode. This mode loads only a few basic services and drops you into command-line mode. You then log in as root and can repair your system using command-line tools [1].</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/6ed50aa0-ffc3-425b-a04c-f1916a020a30.png" alt="" style="display:block;margin:0 auto" />

<p>To do this, before the operating system boots (before the Ubuntu logo appears) we hold down the SHIFT key. Doing so takes us into the GRUB menu.</p>
<p>Once the GRUB menu appears, we follow these steps:</p>
<ul>
<li><p>We click on Advanced options.</p>
</li>
<li><p>In the menu that appears, we press Enter on the entry containing the text recovery mode.</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/a7aca5b3-cb68-465c-897c-dbf2d1c5c2b9.png" alt="Figure 2: The Advanced options menu" style="display:block;margin:0 auto" />

<p>After performing the above, your system restarts and we enter the Recovery menu. We can see the Recovery Menu below:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/c4c80655-1ccf-41de-add7-9fa47951eeb8.png" alt="Figure 3: The Recovery menu" style="display:block;margin:0 auto" />

<p>In the Recovery menu, using the arrow keys on the keyboard, we move to the option Drop to root shell prompt and press Enter. As a result, as we can see in the image below, we successfully log in to the operating system as the root user.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/647c9bf2-b919-427d-b8c2-a884575a3ae1.png" alt="Figure 4: Logged in to the system as the root user" style="display:block;margin:0 auto" />

<p>According to the Ubuntu documentation, in this mode the root partition is accessible as Read Only and must be mounted again with Read/Write access by running the following command:</p>
<pre><code class="language-plaintext">mount -o remount,rw /
</code></pre>
<p>In my experience, however, the root partition was mounted Read/Write by default, without any need to run the command above:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/d907826c-c6de-4a49-8b7c-2da4d093986e.png" alt="Figure 5: root partition" style="display:block;margin:0 auto" />

<p>In this environment we can fix our problem and use the <code>passwd</code> command to change the password of the root user (or any other user).</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/7be11db3-70bb-4036-a3ee-d8f32dfaa134.png" alt="Figure 6: Changing the root user's password" style="display:block;margin:0 auto" />

<h3>2.2- Gaining root Access on CUCM</h3>
<p>When we install this Appliance, by default we have no access to the operating system environment and only have access to a custom user interface from Cisco.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/b35ea1f5-f548-49ad-a09b-16e6b1e99831.png" alt="Figure 7: CUCM's default user interface" style="display:block;margin:0 auto" />

<p>Before we start, we should note 2 points:</p>
<ul>
<li><p>To begin, we need the ISO file of a Linux operating system. Here I use the Arch operating system ISO, which can be downloaded from this link.</p>
</li>
<li><p>You must have access to the CD/DVD of the CUCM system. In this tutorial the CUCM in question was installed under VMware, and we can use its virtual CD/DVD.</p>
</li>
</ul>
<p>Now, to gain access to the CUCM system, we proceed as follows:</p>
<p>We place the downloaded ISO file in the CD/DVD of the CUCM virtual machine. To do this, we right-click on the CUCM virtual machine and click on Settings. We go to the CD/DVD menu and select the path to the ISO file on our system.</p>
<p>Note that the Connect at power on option must be checked.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/1405b116-a65e-49d8-9219-cf44aabe42f3.png" alt="Figure 8: Adding the ISO to the CUCM machine" style="display:block;margin:0 auto" />

<p>Now we right-click on the CUCM virtual machine again and, from the Power menu, we select the last option, Power On to Firmware. Selecting this option takes us into the system's BIOS menu.</p>
<p>Now, using the left and right arrows on the keyboard, we move to the Boot menu and press the + key on the CD-ROM Drive entry until the CD-ROM entry becomes the first Boot option.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/cbd29977-0659-43e0-ae1a-40f3004f9f49.png" alt="Figure 9: The BIOS menu in VMware" style="display:block;margin:0 auto" />

<p>Now, by pressing F10, we save the changes and exit the BIOS. Doing this restarts the system and the Arch operating system boots.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/e9adbc9e-0cf9-404a-aeb3-570e27b3e190.png" alt="Figure 10: The Arch Linux boot menu" style="display:block;margin:0 auto" />

<p>After entering the terminal environment of the Arch operating system, we use the <code>fdisk</code> or <code>lsblk</code> command to find the CUCM root partition where the system files are located. This partition is usually at one of the following paths:</p>
<ul>
<li><p>/dev/sda</p>
</li>
<li><p>/dev/sdb</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/3e91f3b2-4a6e-4bf5-9d40-9995d0db8007.png" alt="Figure 11: Listing the system's partitions" style="display:block;margin:0 auto" />

<p>After finding the root partition, we create a directory in which to mount the partition and then mount the root partition at that path.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/92e45ba2-9337-4e1a-9ba1-02185375189d.png" alt="Figure 12: Mounting the CUCM partition" style="display:block;margin:0 auto" />

<p>Now, with the command <code>arch-chroot /mnt/cucm</code>, we can enter the operating system's root partition.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/98cdd9ce-a23e-496d-982e-b7ed900c27d8.png" alt="Figure 13: Performing the chroot operation into the CUCM file system" style="display:block;margin:0 auto" />

<p>chroot is an operation that sets a new path as the root path for the current process and its child processes. A program running in this environment cannot access files and paths outside the path designated as root. This new space is called a chroot jail. [8] [9]</p>
<p>A chroot environment requires a complete file system in order to function correctly. Essential paths such as /lib, /bin, /usr, as well as the libraries and binaries required by the commands, must also be present. The chroot function should not be used for security purposes, for fully isolating a process, or for restricting file system calls.</p>
<p>To have a chroot environment on Linux, the kernel virtual file systems and configuration files must also be mounted or copied from the host into the chroot. [10]</p>
<pre><code class="language-plaintext"># Mount Kernel Virtual File Systems
TARGETDIR="/mnt/chroot"
mount -t proc proc $TARGETDIR/proc
mount -t sysfs sysfs $TARGETDIR/sys
mount -t devtmpfs devtmpfs $TARGETDIR/dev
mount -t tmpfs tmpfs $TARGETDIR/dev/shm
mount -t devpts devpts $TARGETDIR/dev/pts

# Copy /etc/hosts
/bin/cp -f /etc/hosts $TARGETDIR/etc/

# Copy /etc/resolv.conf
/bin/cp -f /etc/resolv.conf $TARGETDIR/etc/resolv.conf

# Link /etc/mtab
chroot $TARGETDIR rm /etc/mtab 2&gt; /dev/null
chroot $TARGETDIR ln -s /proc/mounts /etc/mtab
</code></pre>
<p>For more information about chroot, see links [8], [9], [10] and [11] (recommended).</p>
<p>Now that we have gained access to the root partition, we can change the root user's password and set a Shell for the root user, since by default no Shell is set for the root user.</p>
<p>To change the password, it is enough to enter the command <code>passwd root</code> and set the password we want for the root user.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/be1cd3ba-59b7-42f4-b9ae-691b438fca4f.png" alt="Figure 14: Changing the root user's password" style="display:block;margin:0 auto" />

<p>To set a Shell for the root user, we modify the passwd file as follows:</p>
<pre><code class="language-plaintext">vim /etc/passwd
</code></pre>
<p>In this file, we find the following entry on the first line and change <code>sbin/nologin</code> to <code>bin/bash</code>, then save the changes.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/a2a0841e-9864-4ed2-a515-aac23815d7cd.png" alt="Figure 15: The default text" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/18d9a9f8-d81c-40a4-abcb-c64443eb56b8.png" alt="Figure 16: The modified text" style="display:block;margin:0 auto" />

<p>Now we must permit the root user to log in over SSH. To do this, we enter the following command:</p>
<pre><code class="language-plaintext">vim /etc/ssh/sshd_config
</code></pre>
<p>We then find the <code>PermitRootLogin</code> line and change its value from <code>no</code> to <code>yes</code>, then save the changes.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/16908029-0c0b-4786-945d-900f461b0841.png" alt="Figure 17: The default text" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/a5a2477e-840a-4fdd-bca6-1dbd9ac72651.png" alt="Figure 18: The modified text" style="display:block;margin:0 auto" />

<p>Next, we must change the value of Selinux from enforcing to permissive. To do this, using the vim text editor we open the file located at <code>etc/selinux/config</code> and change the value in front of Selinux from <code>enforcing</code> to <code>permissive</code>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/bc47bf73-7bc2-44ac-a670-73bf0028b75a.png" alt="Figure 19: Before applying the changes" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/abf904f3-8e94-4423-ba59-15ebeb3f439e.png" alt="Figure 20: After applying the changes" style="display:block;margin:0 auto" />

<p>Now, with the root user's password in hand, we can access the CUCM system over SSH:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/f80740ef-d665-4306-bd13-cca6fce8fe1e.png" alt="Figure 21: Successful login to the system as the root user" style="display:block;margin:0 auto" />

<h3>2.3- Password Recovery Using GRUB Parameters</h3>
<p>In this method, by editing the GRUB parameters we can log in to the system without having the password.</p>
<p>In this section, to demonstrate this method, we use the Ubuntu operating system. Note that this method can be performed on all Linux systems.</p>
<p>To recover the password by changing the GRUB parameters, we proceed as follows:</p>
<p>While the system is booting, before the OS is loaded, we hold down the SHIFT key in order to enter the GRUB screen.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/b50c0fbe-3aef-44c8-9460-3a158aded2dd.png" alt="Figure 22: Guess what? It's GRUB Menu Again" style="display:block;margin:0 auto" />

<p>We move to the Ubuntu entry and press the <code>e</code> key. Using this key we can modify the commands and parameters used before the operating system boots.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/f44ad414-0680-47bf-a2a7-cdb3b2e317f0.png" alt="Figure 23: The GRUB Command Line Editor menu" style="display:block;margin:0 auto" />

<p>On the page that opens, using the arrow keys on the keyboard, we look for the line that begins with the word <code>linux</code>:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/435564c1-5eb9-4ec9-82e4-f970f4b1fb89.png" alt="Figure 24: The line in question" style="display:block;margin:0 auto" />

<p>This line is responsible for loading the Linux kernel and passing various parameters to it, and we now explain the meaning of each of them:</p>
<ul>
<li><p><strong>linux</strong>: this command tells GRUB to load the Linux kernel from the path <code>boot/vmlinuz...-generic</code>.</p>
</li>
<li><p><strong>root=UUID</strong>: this parameter specifies the root file system, where the operating system files are stored. The root parameter tells the kernel the path of the root partition.</p>
</li>
<li><p><strong>quiet</strong>: this option reduces the amount of kernel output displayed during boot.</p>
</li>
<li><p><strong>ro</strong>: this parameter means that the root partition should be loaded read-only.</p>
</li>
<li><p><strong>splash</strong>: this option enables the display of a splash screen during boot instead of textual boot messages. A Splash Screen is a graphical or animated image shown while the system boots that hides the text output, making the boot process look simpler and more user-friendly.</p>
</li>
</ul>
<p>For more information about these parameters you can refer to link [2].</p>
<p>Reviewing the other kernel parameters, we come to the <code>init</code> parameter [2]:</p>
<pre><code class="language-plaintext">init= [KNL] Format: &lt;full_path&gt; Run specified binary instead of /sbin/init as init process.
</code></pre>
<p>Using the <code>init</code> parameter we can pass the kernel the path of another binary file to run instead of the init process. The init process is the first process run on the system by the kernel and is responsible for loading and starting the other processes on the system.</p>
<p>Given the explanation above, by adding the following to the end of the <code>linux</code> line we can log in to the system as the root user without needing a password:</p>
<pre><code class="language-plaintext">quiet rw init=/bin/bash
</code></pre>
<p>After editing the kernel parameters, we boot the system using CTRL + X.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/06f33359-8e43-46dd-84cc-bc71433f7d6e.png" alt="Figure 25: The edited kernel parameters" style="display:block;margin:0 auto" />

<p>As you can see in the image below, without needing the password we obtained root access to the system and were able to change the root user's password.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/83b1bcb5-9fb9-48aa-8a2b-519d78f94a5d.png" alt="Figure 26: Successful login to the system" style="display:block;margin:0 auto" />

<p>In the previous sections we examined the common methods for recovering the password of Linux systems, as well as a method for gaining Shell access on CUCM. Now we turn to a scenario in which editing the kernel parameters or entering Rescue Mode requires a password.</p>
<h2>3- A Special Scenario</h2>
<p>On one of the projects, an OVF file was handed to me for assessment. After evaluating the usual methods, it became clear that, because of a password, editing the kernel parameters and entering Rescue Mode were not possible.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/4ff403e8-7e8e-4ced-a848-722e5e78b2e3.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/0d9a8671-d2dc-45f6-8234-bcbd516e45c4.png" alt="" style="display:block;margin:0 auto" />

<h3>3.1- About the Open Virtualization Format (OVF) File</h3>
<p>The Open Virtualization Format (OVF) is an open standard for packaging and distributing virtual appliances or, more generally, software that runs on virtual machines [5]. In simpler terms, the OVF export of a virtual machine contains all the components of that system along with all of its partitions.</p>
<p>We can view OVF files using archive management software such as 7-Zip. After opening the OVF file of the virtual machine in question in 7-Zip, we will have access to the following files:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/6f506915-0d34-4579-abc0-9469037f64a6.png" alt="Figure 29: The files contained in the OVF file" style="display:block;margin:0 auto" />

<p>We can also run the OVF file in virtualization software such as VMware. After doing so, we arrive at the following files:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/13a675da-de27-4f3a-bad4-c966b4b346e3.png" alt="Figure 30: The files contained in the OVF file" style="display:block;margin:0 auto" />

<p>Among the files we see, the most important is the file with the VMDK extension, which we discuss in the next section.</p>
<h3>3.2- About the Virtual Machine Disk (VMDK) File</h3>
<p>VMDK (short for Virtual Machine Disk) is a file format that describes containers for virtual disks intended for use in virtual machines such as VMware Workstation or VirtualBox. [6]</p>
<p>In simple terms, this file contains all of the virtual machine's system partitions. If the machine's virtual disk is not encrypted using FDE, we can simply mount the VMDK file on our own system and view and edit the virtual machine's files. Next, we will look at how to mount a VMDK file on a Linux system.</p>
<h4>3.2.1- How to Mount a VMDK File</h4>
<p>To mount a VMDK file, we enter the following commands:</p>
<pre><code class="language-plaintext">sudo modprobe nbd
</code></pre>
<p>This command loads the Linux kernel module named <code>nbd</code>. NBD, or Network Block Device, is a kernel module that allows remote block devices to be attached to the local system. By loading this module, your system will be able to use network block devices, such as virtual disks or disks located on other servers.</p>
<p>In general, <code>modprobe</code> is an administrative tool used to load or remove kernel modules.</p>
<pre><code class="language-plaintext">sudo qemu-nbd -c /dev/nbd1 /path/to/REDACTED-OS-disk1.vmdk
</code></pre>
<p>This command uses the <code>qemu-nbd</code> tool, which is part of the QEMU tools (virtualization tools). This tool is used to attach virtual disks (of various types such as VMDK, QCOW2, and so on) to the system.</p>
<p>The <code>c</code> parameter specifies that you want to attach a virtual disk file to a particular NBD device such as <code>/dev/nbd1</code>. Here, the VMDK file located at the given path is attached to the NBD1 device, and the system recognizes it as a block disk.</p>
<pre><code class="language-plaintext">sudo fdisk -l /dev/nbd1
</code></pre>
<p>This command is used to display information about the partitions of the <code>/dev/nbd1</code> device. <code>fdisk</code> is a disk management tool on Linux that can be used to view and manage partitions.</p>
<p>The <code>-l</code> parameter displays a list of all partitions present on the specified disk. By running this command you can see what kinds of partitions the VMDK virtual disk attached to NBD1 has and how large they are.</p>
<p>As you can see in the image below, we successfully attached the VMDK file at the path <code>dev/nbd1</code>:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/1b4f0db8-b1b7-4add-a40a-66b672a709a8.png" alt="Figure 31: The partitions present in the VMDK file" style="display:block;margin:0 auto" />

<p>So far we have been able to reach the partitions present in the VMDK file. Next we examine the password in GRUB and try to replace the GRUB password present on the virtual machine with our own password.</p>
<h3>3.3- About the GRUB Password</h3>
<p>Grub2 supports the ability to create a password for the Menu or the Terminal. Depending on their needs, a user can set a password for the entire Menu or for parts of the Menu. This password can be stored either encrypted or as Clear-Text. [3]</p>
<p>We can protect Grub2 with a password in the following two ways [4]:</p>
<ol>
<li><p>A password is required to modify menu entries, but is not required to boot menu entries.</p>
</li>
<li><p>A password is required both to modify menu entries and to boot menu entries.</p>
</li>
</ol>
<h3>3.4- Finding the GRUB Password</h3>
<p>From an initial review of the VMDK file, getting into and accessing this system seemed impossible. On further examination, and with the help of Mr. Hamid Kashfi, I realized that as long as the operating system boots — that is, we reach the operating system's Login screen — bypassing the Grub password is possible!</p>
<p>To find where the Grub password is stored, we first mount the nbd1p2 partition, which has 1 gigabyte of storage space (see Figure 31), on our own system:</p>
<pre><code class="language-plaintext">sudo mount /dev/nbd1p2 /mnt/virtualdisk/nbd1p2
</code></pre>
<p>Examining this partition's files, we notice the grub2 directory:</p>
<pre><code class="language-plaintext">ls /mnt/virtualdisk/nbd1p2
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/552abef7-6f58-4894-b578-69dd18592b6a.png" alt="Figure 32: The directories present in the partition" style="display:block;margin:0 auto" />

<p>Examining the files present in grub2, we arrive at the following information:</p>
<pre><code class="language-plaintext">ls /mnt/virtualdisk/nbd1p2/grub2/
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/c7d50d3e-7616-4c29-aef2-0af4f01d273a.png" alt="Figure 33: The files present in the grub directory" style="display:block;margin:0 auto" />

<p>Examining the files in the grub2 directory, we notice the file <code>user.cfg</code>. When we create a password to protect the editing of Grub2 entries, the file <code>user.cfg</code> is created, which contains the hash of the Grub password. [7]</p>
<p>This file contains the following information:</p>
<pre><code class="language-plaintext">cat /mnt/virtualdisk/nbd1p2/grub2/user.cfg
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/be411fcc-9361-4447-abec-addd641c4b57.png" alt="Figure 34: The grub password hash" style="display:block;margin:0 auto" />

<p>Examining the information obtained, we conclude that by substituting our own password hash for this hash, we can enter the Grub command editing menu.</p>
<h3>3.5- Creating a Grub Password and Replacing It</h3>
<p>To create a Grub password, we use the <code>grub-mkpasswd-pbkdf2</code> command. [7] After running the above command, the desired password is taken from the user, after which the password hash is displayed on the terminal.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/d457020c-de64-4d96-80f9-6412a352e164.png" alt="Figure 35: Creating the grub password" style="display:block;margin:0 auto" />

<p>Now we substitute our own password hash for the password hash present in the <code>user.cfg</code> file:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/d3c4df02-b67f-41d8-a24e-25339ea8b827.png" alt="Figure 36: Replacing the grub password hash" style="display:block;margin:0 auto" />

<p>Next we verify that what we did worked, and try, by changing the kernel parameters, to break into the target system and change the root user's password.</p>
<h3>3.6- ROOT</h3>
<p>To verify the change we made, while the target virtual machine is booting we hold down the SHIFT key so that the Grub screen appears.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/523cc721-b12f-4a99-a0d3-b63c45dfe743.png" alt="Figure 37: The Grub menu" style="display:block;margin:0 auto" />

<p>Then, by pressing the <code>e</code> key on the entry in question, the user is prompted for a username and password. Here, with the username <code>root</code> and the password we set earlier, we enter the Grub command screen.</p>
<p>Just as we did on Ubuntu, we enter the following at the end of the line responsible for loading the Linux kernel:</p>
<pre><code class="language-plaintext">rw init=/bin/bash
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/208fdca1-9b02-485d-9619-1349539542dc.png" alt="Figure 38: Changing the kernel parameter" style="display:block;margin:0 auto" />

<p>Then, using CTRL + X, we start booting the system.</p>
<p>As we can see in the image below, we successfully broke into this system and changed the root user's password.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6915c7f949601a992bf84ff8/e69c0a33-3cee-450a-961d-828bdb28e920.png" alt="Figure 39: ROOT" style="display:block;margin:0 auto" />

<h2>4- Conclusion</h2>
<p>As we have read in this post, there are many ways to obtain the password of a Linux system to which we have physical access; some of these ways are simple and some are a little more complex. As penetration testing professionals, it is our duty to learn these methods and use them in the course of our work.</p>
<h2>6- References</h2>
<p>[1] <a href="https://wiki.ubuntu.com/RecoveryMode">https://wiki.ubuntu.com/RecoveryMode</a></p>
<p>[2] <a href="https://docs.kernel.org/admin-guide/kernel-parameters.html">https://docs.kernel.org/admin-guide/kernel-parameters.html</a></p>
<p>[3] <a href="https://help.ubuntu.com/community/Grub2/Passwords">https://help.ubuntu.com/community/Grub2/Passwords</a></p>
<p>[4] <a href="https://docs.redhat.com/en/documentation/red%5C_hat%5C_enterprise%5C_linux/8/html/managing%5C_monitoring%5C_and%5C_updating%5C_the%5C_kernel/assembly%5C_protecting-grub-with-a-password%5C_managing-monitoring-and-updating-the-kernel#proc%5C_setting-password-protection-only-for-modifying-menu-entries%5C_assembly%5C_protecting-grub-with-a-password">https://docs.redhat.com/en/documentation/red\_hat\_enterprise\_linux/8/html/managing\_monitoring\_and\_updating\_the\_kernel/assembly\_protecting-grub-with-a-password\_managing-monitoring-and-updating-the-kernel#proc\_setting-password-protection-only-for-modifying-menu-entries\_assembly\_protecting-grub-with-a-password</a></p>
<p>[5] <a href="https://en.wikipedia.org/wiki/Open%5C_Virtualization%5C_Format">https://en.wikipedia.org/wiki/Open\_Virtualization\_Format</a></p>
<p>[6] <a href="https://en.wikipedia.org/wiki/VMDK">https://en.wikipedia.org/wiki/VMDK</a></p>
<p>[7] <a href="https://docs.redhat.com/en/documentation/red%5C_hat%5C_enterprise%5C_linux/8/html/managing%5C_monitoring%5C_and%5C_updating%5C_the%5C_kernel/assembly%5C_protecting-grub-with-a-password%5C_managing-monitoring-and-updating-the-kernel#proc%5C_setting-password-protection-only-for-modifying-menu-entries%5C_assembly%5C_protecting-grub-with-a-password">https://docs.redhat.com/en/documentation/red\_hat\_enterprise\_linux/8/html/managing\_monitoring\_and\_updating\_the\_kernel/assembly\_protecting-grub-with-a-password\_managing-monitoring-and-updating-the-kernel#proc\_setting-password-protection-only-for-modifying-menu-entries\_assembly\_protecting-grub-with-a-password</a></p>
<p>[8] <a href="https://man7.org/linux/man-pages/man2/chroot.2.html">https://man7.org/linux/man-pages/man2/chroot.2.html</a></p>
<p>[9] <a href="https://wiki.archlinux.org/title/Chroot">https://wiki.archlinux.org/title/Chroot</a></p>
<p>[10] <a href="https://en.wikipedia.org/wiki/Chroot#Linux%5C_host%5C_kernel%5C_virtual%5C_file%5C_systems%5C_and%5C_configuration%5C_files">https://en.wikipedia.org/wiki/Chroot#Linux\_host\_kernel\_virtual\_file\_systems\_and\_configuration\_files</a></p>
<p>[11] <a href="https://www.youtube.com/watch?v=8fi7uSYlOdc">https://www.youtube.com/watch?v=8fi7uSYlOdc</a></p>
]]></content:encoded></item></channel></rss>