In the past, we’ve mentioned how the PHP XOR bitwise operator (represented by the caret ^) can be used to encrypt a malware’s source code. This operator makes it more difficult to determine if encrypted code is malicious, or if it is trying to protect a legitimate developer’s code. However, that’s not the only way that XOR can be used to hide malicious data. This is what we will explore today.
XOR Encrypted Requests
Let’s examine how the XOR bitwise operator is used for encryption in PHP.
Here is a general XOR function:
Checking within PHP’s manual reveals the following description:
“If both operands for the […] ^ operators are strings, then the operation will be performed on the ASCII values of the characters that make up the strings and the result will be a string.”
How Does XOR Operate?
PHP malware using XOR will often use two operands, which are defined variables containing strings. The strings used by one of the operand variables are the malicious code (also known as plaintext) that we wish to encrypt. The other operand variable string is what is known as a pre-shared key.
It’s also important to note that XOR operates as a symmetrical form of encryption. This means that we can encrypt and decrypt using the same key.
Let us break this down with a simple example:
Remember that PHP’s ^ (XOR) bitwise operator converts each character to their corresponding ASCII value. This can be checked with an ASCII table (shown below):
After undergoing XOR bitwise operation, we are left with the ASCII decimal values of 69 87 64 64 (or EW@@) after we convert back to ASCII characters. The result is the ciphertext (C), also known as the encrypted content.
This is symmetrically encrypted — so the key (B) to decrypt it back into plaintext (A) is the same key used to encrypt it.
PHP Malware and XOR
In the case of PHP malware, we primarily see it used in three methods.
The First Method
Only the ciphertext (C) in the infected file is stored. It is then decrypted to plain text (A) when a malicious user submits the key (B) in a request. The previously encrypted PHP code can then be executed.
The plaintext (A) string is malicious code that attackers then encrypt on their end by using XOR with a key (B) string. The result ends up being the ciphertext (C), which is unreadable as PHP code.
This ciphertext (C) is then added to a compromised websites’ file(s), along with some PHP code that uses some user-provided data (e.g via $_POST). This allows the hacker to send the value of the key and use the infected PHP file to decrypt the ciphertext (C) back to plaintext (A) (their malicious PHP code), then execute it using something like the eval() function.
Users that open the infected PHP file will only see the ciphertext (C); as they are missing the (B) key, they therefore cannot easily decrypt the encrypted content (C). This is what the hacker wants, as it keeps their malicious PHP code unreadable until they submit a request containing the necessary key (B) string.
One problem is that, depending on the amount of encrypted malicious PHP code, the ciphertext (C) in the infected file can be large and attract suspicion when viewed in a file editor.
The Second Method
Only the key (B) in the infected file is stored. The hacker then provides the ciphertext (C) in their request and it is XOR’ed with the existing key value in the file to form our plaintext (A) — which is then executed.
For this second method, let’s take a look at a recent backdoor found in a file named “01f008ec.php” within the root directory of an infected website.
The backdoor starts with a isset condition that must be satisfied in the request sent to the file — in this case, the HTTP cookie containing the key value. This cookie value, which must match the hard-coded value of the defined $auth variable, is then encoded using str_rot13( and used to define the $key (B) variable.
Before the XOR operation, the file will use file_get_contents(‘php://input’) to read raw data through GET/POST requests (XOR encoding may add special characters that can be broken if not transmitted raw) to the malicious file. After that, it’s split into an array using str_split( and defined with the variable $part within a foreach loop.
We can see the malicious file’s code eventually evaluates code through a separate variable, eval($res) letting us know that the variable $res should contain the plaintext PHP code in order to be successfully executed.
This is a great example of the properties of symmetrical cryptography. The hacker uses the key (B) value to create the unreadable ciphertext (C) on their end. Next, the ciphertext (C) is submitted to the infected file via GET/POST request where it will be XOR’ed with the key (B) once more. The result is a plaintext (A) value that contains the malicious PHP code to be executed by the eval( function.
It’s important to note that the plaintext (A) gets evaluated, so you won’t ever see it — nor the ciphertext (C) being sent to the infected file (unless you are logging them or otherwise inspecting packet contents).
One advantage with using this method is that even if HTTP requests are inspected (e.g. by a firewall), website owners wouldn’t see the plaintext PHP. This can aid in evading detection. Another advantage is that the infection in the file can be much smaller (~235 characters on one line) than the previous method, which can have thousands of characters. This can also help prevent administrators from identifying malicious changes to files.
The Third Method
The third method we see shares these same advantages, along with one more.
The infected file does NOT contain any hard-coded ciphertext (C) or a key (B); instead, the hacker provides the ciphertext and key as two strings in a crafted HTTP request to the infected file. These are then XOR’ed to produce the cleartext (A), which can then be executed.
This third method doesn’t have the key value (B) hardcoded into the infected file’s coding like our previous example, therefore requiring interception of the HTTP request so that the key value (B) can be used to decrypt/encrypt the ciphertext (C).
In conclusion, XOR bitwise operations in PHP malware can help hackers evade certain security controls. However, their symmetric cryptography means that anyone that knows the pre-shared secret key can decrypt/encrypt using it.
Users who believe that their site may be infected with a PHP backdoor can refer to our hacked website guides for cleanup instructions, or reach out to our remediation team for assistance — we’re always happy to lend a hand.
If you would like to receive email notifications for technical website security posts, subscribe to our blog feed.