Foreword
PHP is a general open source scripting language. Its syntax mixes the syntax of excellent languages such as C, Java, and Perl. In addition, it also provides a large number of function libraries for developers to use. However, if used improperly, PHP can also bring very large security risks to applications.
In this article, we will conduct an in-depth analysis of some problems that often occur in PHP applications, especially when we use "==" (comparison operator) to perform string comparisons, which may Some security issues arise. Although many articles have recently discussed this topic, I decided to discuss how to use this problem to penetrate and attack targets from the perspective of "black box testing". First, I will analyze the root cause of this problem so that we can have a deeper understanding of its working mechanism, so as to ensure that we can avoid this security problem as much as possible.
Description of the problem
In 2011, the PHP official bug tracking system discovered that when strings and numbers were compared, the program would experience some very strange phenomena. From a security perspective, this issue is not actually a security issue. For example, you can see the following code:
In fact, this situation will occur when using comparison operators like "==" to operate. The problem in the above example cannot be regarded as a vulnerability, because it is a function called "type conversion" provided by PHP. Essentially, when we use specific comparison operators (such as ==, !=, ) to operate, PHP will first try to determine the data type participating in the comparison. However, such a type conversion mechanism may cause the calculation results to be greatly different from our expected results, and will also cause very serious security issues. Security research experts wrote in a full disclosure report on the issue: This type conversion mechanism may lead to privilege escalation and even make the program's password verification process unsafe.
Gynvael wrote a classic article on this topic. The data types covered by the PHP equal sign operator "==" are very wide. We provide you with a relatively complete comparison reference list and give some Example, the specific content is as follows:
As you can see, when we use "==" to compare these numerical strings, what is involved in the comparison is the actual size of the numbers in the string, from safety From this perspective, this is a very interesting question. In this case, you can use scientific notation to represent a number and put it in a string, and PHP will automatically treat it as a number type. The reason why we get such an output type is because PHP uses a hash algorithm (usually represented by a hexadecimal value) for processing. For example, if a number is 0, PHP will automatically convert its type during the loose comparison, but its value will always be 0. For a given hashing algorithm, the password may become replaceable. For example, when a password hash is converted into a number using scientific notation, it will likely match other password hashes. In this way, even a completely different password may still pass the system's verification. But what’s interesting is that when comparing certain numbers expressed in scientific notation, the results may surprise you:
Consider this issue from the perspective of "black box testing"
From the perspective of static analysis, these security issues seem a bit ordinary. But if we look at these problems from a black box perspective, what insights can we get? For any user account in the application, if the application uses the most popular hashing algorithm (such as SHA1 and MD5) to process passwords, and you use PHP's loose comparison when verifying password hashes, then security issues may arise at this time. We can now consider a typical penetration test. You can create a normal account, set the password to one of the passwords with a similar hash value, and then use the other password to log in. Obviously, the security of your system depends entirely on the hashing algorithm you use. So, assuming you're not using a "Salt" value in your hashing algorithm, you're going to have to use at least two different hashing algorithms for your passwords.
Now, before we study these password combinations, we should also consider one thing - the password requirements. Because before we analyze these passwords and hash algorithms, we must first ensure that the initial password we set meets the password complexity requirements, otherwise our analysis and research will be meaningless. Therefore, we have to make sure that our password is at least eight characters long and contains uppercase and lowercase letters, numbers, and at least one special character: The details are as follows:
import random
import hashlib
import re
import string
import sys
prof = re.compile("^0+ed*$") # you can also consider: re.compile("^d*e0+$")
prefix = string.lower(sys.argv[1])+'!'+string.upper(sys.argv[1])+"%s"
num=0
while True:
num+=1
b = hashlib.sha256(prefix % num).hexdigest()
if (b[0]=='0' and prof.match(b)):
print(prefix+str(num),b)
Copy after login
For this, I specially wrote a Python script, although I No effort has been made to optimize the performance of this script, but with the help of the PyPy compiler, this well-written script runs stably on all available CPU cores of my AMD FX8350. In addition, I also used the hash function in the hashlib library, and in order to avoid encountering the process synchronization problem of Python GIL, I also generated an independent process to process the password data. Not only that, I also used a very sophisticated technique to generate a different prefix for each password, as shown in the code above.
Analysis results
After more than an hour of analysis, I got the SHA1 values of the four passwords. To my surprise, it took less time to get the MD5 values of the four passwords.
The calculation results of the passwords are very similar, as shown below:
You can randomly select two passwords for comparison. The comparison demonstration results are as follows:
If you cannot get the password as shown above Calculate the results, then you should feel lucky. You could try bundling the username and password together and then using a hash algorithm with a "salt" value to calculate it. You only need to modify a small part of the code to achieve it. Click "here" to get the modified script.
Solution
PHP provides us with a solution. If you want to compare hash values, you should use the password_verify() or hash_equals() functions. They perform strict comparisons on data and eliminate some other interfering factors. But please note that the hash_equals() function can also be used for string comparison.
Analysis Conclusion
Although our analysis steps are a bit too complicated to execute, from the perspective of black box testing, the method we described may be able to provide you with some valuable information. If the password in an application uses such a verification mechanism, the security issues it brings will go beyond the problems of PHP data type conversion itself.
The problem goes far beyond that
The impact of this problem on us goes far beyond that. An attacker can add these passwords to a dictionary file and then perform a brute force attack against all users in the application. Moreover, if there are insecure factors in the password recovery mechanism of the application, the attacker may attack the target account an unlimited number of times until the attack is successful.