<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="http://blog.rm.dev/feed.xml" rel="self" type="application/atom+xml" /><link href="http://blog.rm.dev/" rel="alternate" type="text/html" /><updated>2026-01-15T02:41:17+00:00</updated><id>http://blog.rm.dev/feed.xml</id><title type="html">RM.dev Blog</title><subtitle>Disorganized musings.</subtitle><author><name>Raymond Moul</name></author><entry><title type="html">Examining a Basic WordPress Backdoor</title><link href="http://blog.rm.dev/2025/04/14/wordpress-backdoor-explained.html" rel="alternate" type="text/html" title="Examining a Basic WordPress Backdoor" /><published>2025-04-14T00:00:00+00:00</published><updated>2025-04-14T00:00:00+00:00</updated><id>http://blog.rm.dev/2025/04/14/wordpress-backdoor-explained</id><content type="html" xml:base="http://blog.rm.dev/2025/04/14/wordpress-backdoor-explained.html"><![CDATA[<p>In this video I examine and test a basic WordPress backdoor script that was found on a client’s website.</p>

<p>This type of backdoor is used to provide an attacker with access to the website even if the original vulnerability that allowed them to compromise the website is patched or removed.</p>

<p><a href="https://github.com/rmmoul/wordpress-malware-samples/blob/main/obfuscated-backdoor-auto-login-as-admin.php">The full, commented, backdoor script can be found here</a>. I’m building a library of WordPress malware samples with explainations of what they do <a href="https://github.com/rmmoul/wordpress-malware-samples/tree/main">in a repository here</a>.</p>

<div class="video-container">
  <iframe src="https://www.youtube.com/embed/CyPWxbLayJk?rel=0" title="WordPress backdoor script example" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe>
</div>]]></content><author><name>Raymond Moul</name></author><category term="Other" /><summary type="html"><![CDATA[In this video I examine and test a basic WordPress backdoor script that was found on a client’s website.]]></summary></entry><entry><title type="html">AES Decryption using JavaScript</title><link href="http://blog.rm.dev/2025/04/07/AES-Decryption-using-JavaScript.html" rel="alternate" type="text/html" title="AES Decryption using JavaScript" /><published>2025-04-07T00:00:00+00:00</published><updated>2025-04-07T00:00:00+00:00</updated><id>http://blog.rm.dev/2025/04/07/AES-Decryption-using-JavaScript</id><content type="html" xml:base="http://blog.rm.dev/2025/04/07/AES-Decryption-using-JavaScript.html"><![CDATA[<p>This is part 2 in my 2 part series on AES encryption and decryption using JavaScript and the Crypto library that is included with modern browsers.</p>

<p><a href="https://blog.rm.dev/2025/04/05/AES-Encryption-using-JavaScript.html">Part 1, AES Encryption using JavaScript, can be read here.</a></p>

<p>You can find the full source here:
<a href="https://github.com/rmmoul/javascrt-aes-encryption">https://github.com/rmmoul/javascrt-aes-encryption</a></p>

<p>I also have a working exmaple running on codpen here:
<a href="https://codepen.io/Raymond-Moul/pen/mydoBoq">https://codepen.io/Raymond-Moul/pen/mydoBoq</a></p>

<p>Much of the actual decryption process is nearly identical to the encryption process, aside from the first step where we cut up the message in its various parts. Many of the functions and methods used are explained in part 1 and skipped here to avoid redundancy.</p>

<p>Here is the full decryption function that we’ll be working through and explaining:</p>

<pre><code>async function decryptMessage(encryptedBase64, password) {
	// Convert the Base64 string back into a Uint8Array.
	const combined = Uint8Array.from(atob(encryptedBase64), c =&gt; c.charCodeAt(0));

	// Extract the salt (first 16 bytes), IV (next 16 bytes), and ciphertext (remaining bytes).
	const salt = combined.slice(0, 16);
	const iv = combined.slice(16, 32);
	const ciphertext = combined.slice(32);

	// Encode the password as Uint8Array.
	const encoder = new TextEncoder();
	const passwordBytes = encoder.encode(password);

	// Import the password as key material.
	const keyMaterial = await crypto.subtle.importKey(
		'raw',
		passwordBytes,
		{ name: 'PBKDF2' },
		false,
		['deriveKey']
	);

	// Derive the same AES-CBC key using PBKDF2 (must use the same salt, iterations, and hash).
	const key = await crypto.subtle.deriveKey(
		{
			name: 'PBKDF2',
			salt: salt,
			iterations: 100000,
			hash: 'SHA-256'
		},
		keyMaterial,
		{ name: 'AES-CBC', length: 256 },
		false,
		['decrypt']
	);

	// Decrypt the ciphertext.
	const decryptedContent = await crypto.subtle.decrypt(
		{
			name: 'AES-CBC',
			iv: iv
		},
		key,
		ciphertext
	);

	// Convert the decrypted bytes back into a string.
	const decoder = new TextDecoder();
	return decoder.decode(decryptedContent);
}
</code></pre>

<h2 id="retrieving-the-salt-iv-and-encrypted-message">Retrieving the salt, IV, and encrypted message</h2>

<p>The first thing the function does is to decode the message text from Base64 and move the data into a Unit8Array so that we can extract the salt, IV, and encrypted message text.</p>

<pre><code>// Convert the Base64 string back into a Uint8Array.
const combined = Uint8Array.from(atob(encryptedBase64), c =&gt; c.charCodeAt(0));

// Extract the salt (first 16 bytes), IV (next 16 bytes), and ciphertext (remaining bytes).
const salt = combined.slice(0, 16);
const iv = combined.slice(16, 32);
const ciphertext = combined.slice(32);

// Encode the password as Uint8Array.
const encoder = new TextEncoder();
const passwordBytes = encoder.encode(password);
</code></pre>

<p>Our salt and IV are both 16 bytes, so we use the slice method to extract the first 16 bytes of the integer array to get the salt and then next 16 bytes to get the IV, leaving the rest of the array which contains the encrypted message.</p>

<p>We then take the password that was passed to the decryption function and convert it to an integer array using the TextEncoder interface.</p>

<h2 id="converting-the-password-into-a-usable-key">Converting the password into a usable key</h2>

<p>This process is nearly identical to the process in the encryption function and is <a href="https://blog.rm.dev/2025/04/05/AES-Encryption-using-JavaScript.html#create-the-encryption-key">explained in part 1</a>, aside from the keyUsages parameter set in the crypto.subtle.deriveKey method where we pass “decrypt” here.</p>

<pre><code>// Import the password as key material.
const keyMaterial = await crypto.subtle.importKey(
	'raw',
	passwordBytes,
	{ name: 'PBKDF2' },
	false,
	['deriveKey']
);

// Derive the same AES-CBC key using PBKDF2 (must use the same salt, iterations, and hash).
const key = await crypto.subtle.deriveKey(
	{
	name: 'PBKDF2',
	salt: salt,
	iterations: 100000,
	hash: 'SHA-256'
	},
	keyMaterial,
	{ name: 'AES-CBC', length: 256 },
	false,
	['decrypt']
);
</code></pre>

<h2 id="decrypting-the-message">Decrypting the message</h2>

<p>We can now decrypt the message using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/decrypt">crypto.subtle.decrypt</a> method.</p>

<pre><code>// Decrypt the ciphertext.
const decryptedContent = await crypto.subtle.decrypt(
	{
		name: 'AES-CBC',
		iv: iv
	},
	key,
	ciphertext
);
</code></pre>

<p>Much like the encrypt method, the decrypt method takes 3 parameters:</p>

<pre><code>decrypt(algorithm, key, data)
</code></pre>

<ul>
  <li>algorithm
    <ul>
      <li>We’re using the AES-CBC algorithm and will pass an AesCbcParams object with two values
        <ul>
          <li>name
            <ul>
              <li>We specify AES-CBC here</li>
            </ul>
          </li>
          <li>iv
            <ul>
              <li>We pass our 16 byte IV here</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li>key
    <ul>
      <li>We pass our derived CryptoKey object</li>
    </ul>
  </li>
  <li>data
    <ul>
      <li>This is our integer array that contains the encrypted message text</li>
    </ul>
  </li>
</ul>

<h2 id="converting-the-decrypted-message-back-to-text">Converting the decrypted message back to text</h2>

<pre><code>// Convert the decrypted bytes back into a string.
const decoder = new TextDecoder();
return decoder.decode(decryptedContent);
</code></pre>

<p>This final step is the simple process of converting the message array back to text using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder/decode">TextDecoder decode()</a> method. The decrypted text is then returned by the function.</p>]]></content><author><name>Raymond Moul</name></author><category term="Other" /><summary type="html"><![CDATA[This is part 2 in my 2 part series on AES encryption and decryption using JavaScript and the Crypto library that is included with modern browsers.]]></summary></entry><entry><title type="html">AES Encryption using JavaScript</title><link href="http://blog.rm.dev/2025/04/05/AES-Encryption-using-JavaScript.html" rel="alternate" type="text/html" title="AES Encryption using JavaScript" /><published>2025-04-05T00:00:00+00:00</published><updated>2025-04-05T00:00:00+00:00</updated><id>http://blog.rm.dev/2025/04/05/AES-Encryption-using-JavaScript</id><content type="html" xml:base="http://blog.rm.dev/2025/04/05/AES-Encryption-using-JavaScript.html"><![CDATA[<p>This is part 1 in a 2 part series on AES encryption and decryption using JavaScript and the Crypto library that is included with modern browsers. We’ll work through the encryption and decryption functions and explain the various working parts.</p>

<p><a href="https://blog.rm.dev/2025/04/07/AES-Decryption-using-JavaScript.html">You can read part 2, about decryption, here.</a></p>

<p>You can find the full source here:<br />
<a href="https://github.com/rmmoul/javascrt-aes-encryption">https://github.com/rmmoul/javascrt-aes-encryption</a></p>

<p>I also have a working exmaple running on codpen here:<br />
<a href="https://codepen.io/Raymond-Moul/pen/mydoBoq">https://codepen.io/Raymond-Moul/pen/mydoBoq</a></p>

<p>Here is the full encryption function that we’ll be working through and explaining:</p>

<pre><code>async function encryptMessage(message, password){
	// Convert strings to Uint8Arrays.
	const encoder = new TextEncoder();
	const passwordBytes = encoder.encode(password);
	const messageBytes = encoder.encode(message);

	// Generate a random salt for key derivation.
	const salt = crypto.getRandomValues(new Uint8Array(16));

	// Import the password as key material.
	const keyMaterial = await crypto.subtle.importKey(
		'raw',
		passwordBytes,
		{ name: 'PBKDF2' },
		false,
		['deriveKey']
	);

	// Derive an AES-CBC key using PBKDF2.
	const key = await crypto.subtle.deriveKey(
		{
			name: 'PBKDF2',
			salt: salt,
			iterations: 100000, // A higher count means better security but slower performance.
			hash: 'SHA-256'
		},
		keyMaterial,
		{ name: 'AES-CBC', length: 256 },
		false,
		['encrypt']
	);

	// Generate a random Initialization Vector.
	const iv = crypto.getRandomValues(new Uint8Array(16));

	// Encrypt the message.
	const encryptedContent = await crypto.subtle.encrypt(
		{
			name: 'AES-CBC',
			iv: iv
		},
		key,
		messageBytes
	);

	// Combine salt, IV, and ciphertext into a single Uint8Array.
	const saltLength = salt.byteLength;
	const ivLength = iv.byteLength;
	const ciphertext = new Uint8Array(encryptedContent);
	const combined = new Uint8Array(saltLength + ivLength + ciphertext.byteLength);

	combined.set(salt, 0);
	combined.set(iv, saltLength);
	combined.set(ciphertext, saltLength + ivLength);

	// Convert combined data to a Base64 string.
	const base64String = btoa(String.fromCharCode(...combined));
	return base64String;
}
	
</code></pre>

<h2 id="encoding-the-message-and-password">Encoding the message and password</h2>

<p>The first thing that we do in the function is to convert the message and password into <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array">Uint8Arrays</a> so that the text is converted to integers in an array. These integer values will be the actual data that is used for the encryption, and later when the message is decrypted those integer numbers will be converted back into text.</p>

<p>We do this with JavsScripts <a href="https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder/encode">TextEncoder</a> and the <a href="https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder/encode">encode() method</a></p>

<pre><code>// Convert strings to Uint8Arrays.
const encoder = new TextEncoder();
const passwordBytes = encoder.encode(password);
const messageBytes = encoder.encode(message);
		
</code></pre>

<h2 id="create-the-encryption-key">Create the encryption key</h2>

<p>In the next section of the function we need to generate a <a href="https://en.wikipedia.org/wiki/Salt_(cryptography)">salt</a>, create a <a href="https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey">CryptoKey object</a> using our password, and then finally <a href="https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveKey">derive the final encryption key</a> using our salt and password.</p>

<pre><code>// Generate a random salt for key derivation.
const salt = crypto.getRandomValues(new Uint8Array(16));

// Import the password as key material.
const keyMaterial = await crypto.subtle.importKey(
	'raw',
	passwordBytes,
	{ name: 'PBKDF2' },
	false,
	['deriveKey']
);

// Derive an AES-CBC key using PBKDF2.
const key = await crypto.subtle.deriveKey(
	{
		name: 'PBKDF2',
		salt: salt,
		iterations: 100000, // A higher count means better security but slower performance.
		hash: 'SHA-256'
	},
	keyMaterial,
	{ name: 'AES-CBC', length: 256 },
	false,
	['encrypt']
);
</code></pre>

<p>The salt is generated using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues">crypto.getRandomValues()</a> function to produce a “cryptographically strong” set of 16 numbers between 0 and 255. You can see an example of a generated salt by running the following in your browser’s dev console:</p>

<pre><code>alert(crypto.getRandomValues(new Uint8Array(16)));
</code></pre>

<p>You should see an alert popup with random values like this:<br />
126,11,104,66,56,207,70,142,171,219,91,89,158,80,250,159</p>

<p>The next step is to create the CryptoKey object using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey">crypto.subtle.importKey</a> method, which takes a number of parameters:</p>

<pre><code>importKey(format, keyData, algorithm, extractable, keyUsages)
</code></pre>

<ul>
  <li>format
    <ul>
      <li>This is to specify the key format that will be returned, and we’re requesting a <a href="https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey#raw">raw key format</a> in our function</li>
    </ul>
  </li>
  <li>keyData
    <ul>
      <li>We’re using the integer array that we generated from our password for the keyData</li>
    </ul>
  </li>
  <li>algorithm
    <ul>
      <li>The importKey method supports a number of algorithms, and we’re using <a href="https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveKey#pbkdf2">PBKDF2</a> which is designed to use low-entropy input like a person’s password.</li>
    </ul>
  </li>
  <li>extractable
    <ul>
      <li>This just specifies whether we want the key to be exportable and we do not need this so we’re setting this value to false.</li>
    </ul>
  </li>
  <li>keyUsages
    <ul>
      <li>We’re going to use this CryptoKey object to derive the key that will be used to encrypt our message. This parameter can take multiple values in an array but we’re only going to pass “deriveKey” since that is all we need to use it for.</li>
    </ul>
  </li>
</ul>

<p>The final step in this section of the function is to derive the key using the crypto.subtle.deriveKey method. This method takes several parameters and our selections are explained below.</p>

<pre><code>deriveKey(algorithm, baseKey, derivedKeyAlgorithm, extractable, keyUsages)
</code></pre>

<ul>
  <li>algorithm
    <ul>
      <li>We’re using the PBKDF2 algorithm again here and we have an <a href="https://developer.mozilla.org/en-US/docs/Web/API/Pbkdf2Params">array of parameters</a> to pass for this algorithm
        <ul>
          <li>name
            <ul>
              <li>PBKDF2</li>
            </ul>
          </li>
          <li>salt
            <ul>
              <li>We’re using our generated salt</li>
            </ul>
          </li>
          <li>iterations
            <ul>
              <li>This sets the number of times the hash function will be executed. A higher number here will take more time (which is good) and we’re setting 100,000 for our iterations</li>
            </ul>
          </li>
          <li>hash
            <ul>
              <li>We’re using the SHA-256 hashing method</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li>baseKey
    <ul>
      <li>We’re passing our keyMaterial CryptoKey object here</li>
    </ul>
  </li>
  <li>derivedKeyAlgorithm
    <ul>
      <li>We’re using the AES CBC (Cipher Block Chaining) mode and need to pass an <a href="https://developer.mozilla.org/en-US/docs/Web/API/AesKeyGenParams">array of parameters</a> here
        <ul>
          <li>name
            <ul>
              <li>This is just the chosen algorithm name of AES-CBC</li>
            </ul>
          </li>
          <li>length
            <ul>
              <li>We’re using the maximum length of 256</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li>extractable
    <ul>
      <li>This just specifies whether we want the key to be exportable and we do not need this so we’re setting this value to false.</li>
    </ul>
  </li>
  <li>keyUsages
    <ul>
      <li>This can take an array of specified usages but we’re just using this key to encrypt so that’s all we’re setting</li>
    </ul>
  </li>
</ul>

<h2 id="creating-an-iv-and-encrypting-the-message">Creating an IV and encrypting the message</h2>

<p>Here we’re creating an <a href="https://en.wikipedia.org/wiki/Initialization_vector">IV (initialization vector)</a> using the same method we used to create our salt. We then use the IV, and our derived key to encrypt our message.</p>

<pre><code>// Generate a random Initialization Vector.
const iv = crypto.getRandomValues(new Uint8Array(16));

// Encrypt the message.
const encryptedContent = await crypto.subtle.encrypt(
	{
		name: 'AES-CBC',
		iv: iv
	},
	key,
	messageBytes
);
</code></pre>

<p>The encryption is done using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt">crypto.subtle.encrypt</a> method which takes a few parameters.</p>

<pre><code>encrypt(algorithm, key, data)
</code></pre>

<ul>
  <li>algorithm
    <ul>
      <li>We’re using the AES-CBC algorithm again here and need to pass <a href="https://developer.mozilla.org/en-US/docs/Web/API/AesCbcParams">an array with two parameters</a> for this algorithm
        <ul>
          <li>name
            <ul>
              <li>The algorithm name, AES-CBC</li>
            </ul>
          </li>
          <li>iv
            <ul>
              <li>We pass the iv value we generated</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li>key
    <ul>
      <li>We pass our key which is the CyrptoKey object we derived previously</li>
    </ul>
  </li>
  <li>data
    <ul>
      <li>This is the integer array that we created from our message text</li>
    </ul>
  </li>
</ul>

<h2 id="combining-our-results-and-converting-them-to-base64-to-share">Combining our results and converting them to Base64 to share</h2>

<p>The final steps combine the various pieces that will be needed to eventually decrypt our message and then return that as a Base64 string that can be easily shared via email or a plain text file.</p>

<pre><code>// Combine salt, IV, and ciphertext into a single Uint8Array.
const saltLength = salt.byteLength;
const ivLength = iv.byteLength;
const ciphertext = new Uint8Array(encryptedContent);
const combined = new Uint8Array(saltLength + ivLength + ciphertext.byteLength);

combined.set(salt, 0);
combined.set(iv, saltLength);
combined.set(ciphertext, saltLength + ivLength);

// Convert combined data to a Base64 string.
const base64String = btoa(String.fromCharCode(...combined));
return base64String;
</code></pre>

<p>The first step here is to get the length of the salt and iv in bytes so that we can reserve enough space for them at the start of the integer array of the final combined data.</p>

<p>We next convert the encrypted message into an integer array and make a final combined integer array that is sized based on the size of the salt, iv, and encrypted message. We do this because a Uint8Array has a fixed size so the combined array needs to be properly sized to fit each item. Then the iv, salt, and message (which are all integer arrays) get inserted into the final combined array using using the set() method and using the lengths of each item to specify the offset in the array to insert each value.</p>

<p>Our final step is to convert the combined integer array into a Base64 string using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/btoa">btoa</a> method, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCharCode">String.fromCharCode</a>, and using <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax">spread syntax</a> to allow the methods to iterate over the combined array.</p>

<p>Our encryptMessage function then returns the Base64 text which can be shared and decrypted using the password that was used to encrypt it.</p>

<p><a href="https://blog.rm.dev/2025/04/07/AES-Decryption-using-JavaScript.html">The decryption function is explained in part 2.</a></p>]]></content><author><name>Raymond Moul</name></author><category term="Other" /><summary type="html"><![CDATA[This is part 1 in a 2 part series on AES encryption and decryption using JavaScript and the Crypto library that is included with modern browsers. We’ll work through the encryption and decryption functions and explain the various working parts.]]></summary></entry><entry><title type="html">Getting Set Up With Github Pages</title><link href="http://blog.rm.dev/2025/04/04/setting-up-github-pages.html" rel="alternate" type="text/html" title="Getting Set Up With Github Pages" /><published>2025-04-04T00:00:00+00:00</published><updated>2025-04-04T00:00:00+00:00</updated><id>http://blog.rm.dev/2025/04/04/setting-up-github-pages</id><content type="html" xml:base="http://blog.rm.dev/2025/04/04/setting-up-github-pages.html"><![CDATA[<p>I set this site up following the tutorial here:<br />
<a href="https://chadbaldwin.net/2021/03/14/how-to-build-a-sql-blog.html">https://chadbaldwin.net/2021/03/14/how-to-build-a-sql-blog.html</a></p>

<p>I also set this up to run under the blog subdomain of my website by following the Github instructions here:<br />
<a href="https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site#configuring-a-subdomain">Github pages, configure a subdomain</a></p>]]></content><author><name>Raymond Moul</name></author><category term="Other" /><summary type="html"><![CDATA[I set this site up following the tutorial here: https://chadbaldwin.net/2021/03/14/how-to-build-a-sql-blog.html]]></summary></entry></feed>