Remote Management plug-ins are very popular with WordPress site administrators. They allow users to perform the same operations on multiple sites at the same time, such as updating to the latest release or installing plug-ins. However, in order to implement these operations, the client plug-in needs to grant large permissions to remote users. Therefore, it is very important to ensure the communication security between the management server and the client plug-in and not be forged by attackers. This article will talk about several available plug-ins. using their vulnerabilities, attackers can even fully compromise the websites that run these plug-ins.
ManageWP, InfiniteWP, and CMS Commander
These three services share the same basic code of the client plug-in (originally the ManageWp implementation, and then the other two have adjusted it ), therefore, they all have the signature Bypass Vulnerability and cause remote code execution.
The Management Server registers the private key of a client plug-in to calculate the message authentication code for each message, instead of asking the user to provide the Administrator credential [MAC, we usually see it as the MAC address of the hardware. Here is the Message Authentication Code]. A message digest is generated when a message uses the message digest algorithm of the shared key. The MAC is then sent along with the message. After receiving the message, the receiver uses the shared key to calculate the received message, generate MAC2, and then compare it with MAC1. Message Digest is used to verify the authenticity and integrity of a message. It is a good method to ensure communication security, however, the implementation defects of the client plug-ins of these three services cause serious vulnerabilities.
A message that is authenticated by helper. class. php is as follows:
// $signature is the MAC sent with the message // $data is part of the message if (md5($data . $this->get_random_signature()) == $signature) { // valid message }
Using non-strict equals means that the type "spoofing" [type conversion] will occur before the comparison. The output of the md5 () function is always a string, but if $ signature is changed to an integer, the type conversion that occurs during comparison is easy to forge a matching MAC. For example, if the actual MAC address starts with "0" or a non-numeric character, then 0 can match. If it is "1xxx", then integer 1 can match, and so on. [This is actually a feature of php, and of course there will be other languages. When a string and a number are not strictly equal to each other, if the first character is a number, it will be converted to the corresponding integer for comparison. If it is not a 0-9 character, it will be treated as 0, php.net description: if you compare a number with a string or a string that involves the content of a number, the string is converted to a value and compared to a value.]
Convert a string to a numeric value:
When a string is taken as a value, the result and type are as follows:
If the string does not contain '.', 'E', or 'e' and Its numeric value is within the integer Range (defined by PHP_INT_MAX), the string is treated as an integer. All other cases are taken as float values.
The starting part of the string determines its value. This value is used if the string starts with a valid value. Otherwise, the value is 0 (0 ). A valid value is an optional positive or negative number followed by one or more numbers (which may have a decimal point) and then an optional index. The index is composed of one or more numbers following 'E' or 'e.
<?php var_dump(0 == "a"); // 0 == 0 -> true var_dump("1" == "01"); // 1 == 1 -> true var_dump("10" == "1e1"); // 10 == 10 -> true var_dump(100 == "1e2"); // 100 == 100 -> true var_dump('abcdefg' == 0); // true var_dump('1abcdef' == 1); // true var_dump('2abcdef' == 2); // true }?>
Unfortunately, attackers can provide an integer as the signature. In init. php, the input request will be decoded using base64_decode (), and the result will be deserialized. The use of Unserialize () means that the type of input data can be controlled. A forged serialized message is as follows:
a:4:{s:9:"signature";i:0;s:2:"id";i:100000;s:6:"action";s:16:"execute_php_code";s:6:"params";a:2:{s:8:"username";s:5:"admin";s:4:"code";s:25:"exec('touch /tmp/owned');";}}
This message uses an integer 0 as the signature, and then executes arbitrary PHP code using the execute_php_code provided by the plug-in.
$signature = 0; // $data is the action concatenated with the message ID $data = 'execute_php_code' . 100000; if (md5($data . $this->get_random_signature()) == $signature) { // valid message if the output of // md5() doesn't start with a digit }
This forged example may not be used directly. First, the key value of the id needs to be greater than the value of the previous valid message. [The added Message ID is used to prevent replay attacks. Today, both requests are forged, there is also replay, which reminds me of CSRF, Cross-Site Request Forgery, is there a man-in-the-middle attack?), followed by an integer used to match the signature, these two requirements can be broken through brute force cracking.
for i from 100,000 to 100,500: for j from 0 to 9: submit request with id i and signature j
The above pseudo-code tries to send a message with a large ID worthy of false, and each ID is matched with a single digital fingerprint ten times [As mentioned earlier, for a string, only one number can be matched during comparison. Here, it is from 0-9 because it can be met in every situation].
This defect can be fixed by using the full equal operator [=] and checking the passed fingerprint. These plug-in services are fixed by using strict equal-sum operators [php.net Description: a = B, then a and B are of the same type; a = B. Determine whether the value is equal after type conversion.]
There are other problems, but they have not taken any action yet. First, this approach involves the weakness of [append the key to $ data and then Hash it]. HMAC [Hash-based Message Authentication Code, generates a message digest as the input key and message.] Second, only the action and Message ID used for the operation are used to create a signature. This means that an active network attacker can change the parameters in the message and the signature is still valid [for example, changing the execute_php_code message to execute arbitrary code]. For protection, MAC should contain the entire message.
[Note: The MD5-based message digest is backward. If possible, these plug-ins use openssl_verify (); * ** the Openssl 1.0.f heartbleed vulnerability announced on February 4, is a century-level vulnerability. **]
Worpit
Worpit is another remote management service, but it uses a client plug-in built from scratch. It also has a forced type conversion vulnerability that allows attackers to log on with administrator privileges.
This plug-in provides a Remote Administrator Logon method. Only Woprit can be used to pass the temporary token value that can be configured by the system. This plugin checks whether the token value provided in the request matches the value stored in the database.
if ( $_GET['token'] != $oWpHelper->getTransient( 'worpit_login_token' ) ) { die( 'WorpitError: Invalid token' ); }
The token is deleted from the database in use. This means that most of the time there is no token in the database. Therefore, the getTransient () method may return false. Non-strict comparison means that any "falsey value, such as string 0, will be considered as a valid token. Log on as an administrator at an example URL:
This token will be deleted from the database once used, which means that there is no token in the database most of the time. Therefore, the call to the getTransient () method may return false. Non-strict comparison is also used, which means that any value equivalent to false, for example, string 0 will be treated as a valid token, and the example of logging in as an administrator: http: // victim /? Worpit_api = 1 & m = login & token = 0
So far, the attacker's site is under the control of the attacker. He has the permission to install malicious plug-ins or modify existing plug-ins.
The solution here is to use it! = Perform other checks and search from the database.
Conclusion:
Be sure to check that the user inputs The expected type and use it in functions that are important to security for strict comparison, such as checking the authentication token.