Abstract:
This is a classic example of random function cracking. In java programs, there are multiple methods to obtain random numbers. However, when we implement a random token and use it for authentication, we usually think of using "System. currentTimeMillis" as soon as possible. This article will explain in detail how a random number is cracked.
Body:
The "System. currentTimeMillis" method returns the number of milliseconds that have elapsed since midnight, January 1, January 1, 1970, UTC. The execution result may be a number similar to "1315395175327". because the number of digits after the execution is millisecond, the execution result is like "random.
A system related to business logic is used to retrieve passwords. First, ask the user to enter his/her email address. The system calculates a token and sends it to the user's email address so that the user can use the token to change the password.
1. Enter the email address.
2. send an email to the user's mailbox.
3. Change the password based on the link in the email address.
That is to say, as long as the token generated by the server to the user can be cracked, the user password can be changed directly.
When token is generated, the following code is used:
Public String genToken (String email ){
String token = email. hashCode () * 21 + System. currentTimeMillis () + "";
Return token;
}
From the code, we can see that the hashcode of the Email remains unchanged when the user's email is fixed. The constant number remains unchanged even if it is multiplied by 21. As long as you know the user's email, you can know the number.
Only System. currentTimeMillis () is random ()
This method seems to be random and can be cracked if conditions permit.
Use the system time to predict and crack java random numbers:
Based on the above process, as long as the attacker submits
Http://www.bkjia.com/user/findpassword. action? Email = 4700012@qq.com
You can send an EMAIL to the attacker's EMAIL address.
======================
Hello, empty heart:
Click the link to reset the password. This link is valid for 24 hours.
Or copy the following link to the address bar of your browser:
Http://www.bkjia.com/user/resetpassword. action? Token = 1315336352414
This email is automatically sent by the system. do not reply to this email directly.
====================
The subsequent token is a random number. Similarly, you can enter the email address of another user (attacker) to send an email. If the time on the server is the same as the execution time on the attacker's machine, the token can be obtained directly without considering the network transmission cost.
Of course, this is impossible.
However, our time speed is basically the same as that of the server. Note: this is not about time consistency. It is about time speed consistency. The local time may be and the server is. When the local time is, the server must be.
Our time is always a different number from the server time.
Network speed. Each transmission is inconsistent. The first request may take 1.020 seconds. The second request may take 0.921 seconds.
It doesn't matter. We try to make it predictable.
Write the following code locally:
========================
Public static void main (String [] args) throws IOException {
System. out. println (I + 1 );
I ++;
System. out. println ("------ mystart ");
System. out. println ("4700012@qq.com". hashCode () * 21
+ System. currentTimeMillis ());
SendPost ("http://www.bkjia.com/user/findpassword. action? Email = 4700012@qq.com ");
System. out. println ("4700012@qq.com". hashCode () * 21
+ System. currentTimeMillis ());
System. out. println ("------ myend ");
System. out. println ("------ user start ");
Long x = "10000@qq.com". hashCode () * 21
+ System. currentTimeMillis ();
System. out. println (x );
SendPost ("http://www.bkjia.com/user/findpassword. action? Email = 10000@qq.com ");
Long y = "10000@qq.com". hashCode () * 21
+ System. currentTimeMillis ();
System. out. println (y );
System. out. println (y-x );
System. out. println ("------ user end ");
}
========================
Code flow, which is described in text:
1. Print the start time of the attacker.
2. send an email to the attacker.
3. Print the attacker's end time.
4. Print the start time of the user to crack
5. send an email to the target user.
6. Print the end time of the user to be cracked
7. When the request server sends an email to the user
The execution result of the program is as follows:
======================================
------ Mystart
1315395175327
1315395175437 // attacker End Time
------ Myend
------ User start
1316945857268
1316945857305 // user end time
37 // user end time minus user start time = network delay.
------ User end
======================================
At the same time, I received an email with the token "1315395156493 ".
Then, based on the following formula:
Attacker end time (known)-time when the server sends emails to the attacker (known) = Time Difference (can be calculated)
User end time (known)-time when the server sends emails to the user (unknown x) = Time Difference (previously calculated)
You can calculate the time for sending emails to users. This time is vague. You also need to add or subtract the current network latency (the program was printed just now) to get a final interval.
Write another code segment:
==================================
Long myendtime = Long. valueOf ("1315395175437"); // The time at which the email is sent to me after being executed locally
Long userendtime = Long. valueOf ("1316945857305"); // The time when I finish sending emails to users locally
Long myservertime = Long. valueOf ("1315395156493"); // time when the server sent me an email
Long userservertime = userendtime-(myendtime-myservertime );
System. out. println (userservertime );
==========================================
This code prints the result:
1316945838361
This is what we predicted. The time range base for the server to send emails to users.
The final number should be the value plus or minus 37 (the network latency at that time), that is, within the range of 1316945838324 to 131694583832474.
The following is handled by WVS:
Quickly, we can get the result that the response content in the first column is different from other ones. We all use 1153B, and only this one is 2685B. This is the answer.
For the answer, visit the page.
As shown in the figure, attackers can crack the token and modify the password directly.
In the case of network attacks, the situations may be inconsistent. If the network delay is long, you can change the network speed to a machine with a low latency. It is best to do this in the middle of the night, with a much higher chance of success.
Advanced Attacks:
Of course, there will be smart development, add MD5 to the final number, that is, the token. This can indeed increase the attack cost, but in essence it is still deceiving itself. Attackers can put a dictionary within a fixed time range.
1316945838361 -- 7bfe0596e68cb9c43bfd0749d835c62d
One-to-one correspondence. In the final arithmetic question, you can query it several times.
We can take the above example and give you an example.
The code is
Public String genToken (String email ){
String token = email. hashCode () * 21 + System. currentTimeMillis () + "";
Return md5 (token );
}
It is basically the same as the previous code, but md5 is finally called when the returned result is returned.
If the result is still the previous one, the server will return:
Token = 8b4a258acdff3bf44ed88d174ed0be20
This token is actually time encryption, and its decryption must be within a certain period of time. First, we need to find features.
Run the current time. First check my time, 1315395175437, which is a long type.
Pass
System. out. println (new SimpleDateFormat ("yyyy-MM-dd HH: mm"). format (new Date (1315395175437 )));
Result:
After constantly changing the number, we can see that
13153951, that is, the first eight digits, representing the number of months.
75437, that is, the last five digits, representing a few seconds.
Even if the server time is silly, today cannot be counted as tomorrow. The difference between the server time and the local server time is several minutes.
So we make a dictionary and input it in the database:
Prefix with "13153951" + 5 digits (00001 to 99999)
Then, add a field in this table, which is the MD5 value of the previous field. If you are not at ease, add a few more places to the field, that is, the fixed prefix "1315395" + 6 digits, and so on, the database will not be very large.
What is the use of this dictionary?
As mentioned above, the server will send an email to me, telling me that Token = 8b4a258acdff3bf44ed88d174ed0be20. The numbers corresponding to this md5 must be in this dictionary, so you can find this md5 from the dictionary directly.
The subsequent process is consistent with the previous cracking.
Paste the result again:
======================================
------ Mystart
1315395175327
1315395175437 // attacker End Time
------ Myend
------ User start
1316945857268
1316945857305 // user end time
37 // user end time minus user start time = when the requesting server sends an email to the user, that is, network latency.
------ User end
======================================
Then, according to the formula, of course, 1316945838361 will be calculated, which is predicted by me. The base of the time range for the server to send emails to users.
The final number should be the value plus or minus 37 (the network latency at that time), that is, within the range of 1316945838324 to 131694583832474.
Encrypt all the numbers in the preceding range and use md5 to make them into a dictionary. You can run them again in wvs to get the result.
The above is purely speculative, and there is no sample test, but the idea is correct.
Advanced again
From the above content, we know that we don't see token, so we can't take it for granted. From the perspective of black box testing, we can even do such an automated thing, this allows you to quickly crack the attack.
When we see that an md5 token exists, perform the following steps.
Write a small program and automate the following processes as much as possible:
1. Get the current time. You can add a hash with the username prefix or an email or another hash. In short, the token content is related to the user and is fixed, it is related to the user name and email that we entered during registration. The username or email + random number are arranged and combined to take the first three steps.
2. the time range is set to within 1 hour (the first few digits have fixed prefixes) to generate an md5 dictionary.
3. Get the token of your account, and then get the result in the dictionary.
4. If Step 3 is successful, you can determine whether the vulnerability exists. The formula is used to calculate the time base of the token provided by the server to the user. The time difference between positive and negative values is used as the md5 dictionary.
5. WVS runs the dictionary once to check the size of the data returned by the server and obtain the user's token.
If we already have code to generate tokens, just like the example in the article, we can omit the steps of the algorithm. When token is generated, many people must have made this mistake. This article focuses on the attack ideas. As for the repair solution, you will not be able to understand it.
By kxlzx www.inbreak.net