$myStr = $_GET['myStr'];
if ($myStr == md5($myStr)) echo "ok\n";
I know there is a type jugglying in the code, but in my tests I couldn't find an input that satisfies the condition.
No, you cannot find that myStr value as it would come down to finding a (first degree) pre-image for MD5. Although MD5 has been broken for collision resistance, you should not be able to find a pre-image. More information here.
I'm presuming there that your code amounts to finding y = md5(y). y = md5(x) is a more general assumption and it is described in the Wikipedia article linked to above that it is impossible to find such H(x), even for MD5.
That doesn't mean that you should use MD5. Please use SHA-256, SHA-512 or indeed one of the SHA-3 functions. Even if MD5 hasn't been broken that far, it has been broken enough not to be used anymore; "Attacks always get better; they never get worse."
Let's start from the beginning. I will provide an example so i may help you maybe understand better.
In the first line you have $myStr = $_GET['myStr'];
I will just assume you will get this variable from your url like this :
http://localhost/md5Project.php?myStr=test
This will give your variable $myStr the value "test".
Moving forward in your if statement you have:
if ($myStr == md5($myStr)
this will never be true because $myStr value is "test" and md5($myStr) value is 098f6bcd4621d373cade4e832627b4f6 so basically you compare 2 strings with values "test" and "098f6bcd4621d373cade4e832627b4f6problem" which will always lead to false.
Related
I am trying to solve a CTF in which the juggling type should be used. The code is:
if ($_GET["hash"] == hash("ripemd160", $_GET["hash"]))
{
echo $flag;
}
else
{
echo "<h1>Bad Hash</h1>";
}
I made a script in python which checks random hashes in ripemd160 that begins with "0e" and ends with only numbers. The code is:
def id_generator(size, chars=string.digits):
return ''.join(random.choice(chars) for _ in range(size))
param = "0e"
results = []
while True:
h = hashlib.new('ripemd160')
h.update("{0}".format(str(param)).encode('utf-8'))
hashed = h.hexdigest()
if param not in results:
print(param)
if hashed.startswith("0e") and hashed[2:].isdigit():
print(param)
print(hashed)
break
results.append(param)
else:
print("CHECKED")
param = "0e" + str(id_generator(size=10))
Any suggestions on how to solve it? Thank you!
There seems to be a bit of misunderstanding in the comments, so I'll start by explaining the problem a little more:
Type juggling refers to the behaviour of PHP whereby variables are implicitly cast to different data types under certain conditions. For example, all the following logical expressions will evaluate to true in PHP:
0 == 0 // int vs. int
"0" == 0 // str -> int
"abc" == 0 // any non-numerical string -> 0
"1.234E+03" == "0.1234E+04" // string that looks like a float -> float
"0e215962017" == 0 // another string that looks like a float
The last of these examples is interesting because its MD5 hash value is another string consisting of 0e followed by a bunch of decimal digits (0e291242476940776845150308577824). So here's another logical expression in PHP that will evaluate to true:
"0e215962017" == md5("0e215962017")
To solve this CTF challenge, you have to find a string that is "equal" to its own hash value, but using the RIPEMD160 algorithm instead of MD5. When this is provided as a query string variable (e.g., ?hash=0e215962017), then the PHP script will disclose the value of a flag.
Fake hash collisions like this aren't difficult to find. Roughly 1 in every 256 MD5 hashes will start with '0e', and the probability that the remaining 30 characters are all digits is (10/16)^30. If you do the maths, you'll find that the probability of an MD5 hash equating to zero in PHP is approximately one in 340 million. It took me about a minute (almost 216 million attempts) to find the above example.
Exactly the same method can be used to find similar values that work with RIPEMD160. You just need to test more hashes, since the extra hash digits mean that the probability of a "collision" will be approximately one in 14.6 billion. Quite a lot, but still tractable (in fact, I found a solution to this challenge in about 15 minutes, but I'm not posting it here).
Your code, on the other hand, will take much, much longer to find a solution. First of all, there is absolutely no point in generating random inputs. Sequential values will work just as well, and will be much faster to generate.
If you use sequential input values, then you also won't need to worry about repeating the same hash calculations. Your code uses a list structure to store previously hashed values. This is a terrible idea. Searching for an item in a list is an O(n) operation, so once your code has (unsuccessfully) tested a billion inputs, it will have to compare every new input against each of these billion inputs at each iteration, causing your code to grind to a complete standstill. Your code would actually run a lot faster if you didn't bother checking for duplicates. When you have time, I suggest you learn when to use lists, dicts and sets in Python.
Another problem is that your code only tests 10-digit numbers, which means it can only test a maximum of 10 billion possible inputs. Based on the numbers given above, are you sure this is a sensible limit?
Finally, your code is printing every single input string before you calculate its hash. Before your program outputs a solution, you can expect it to print out somewhere in the order of a billion screenfuls of incorrect guesses. Is there any point in doing this? No.
Here's the code I used to find the MD5 collision I mentioned earlier. You can easily adapt it to work with RIPEMD160, and you can convert it to Python if you like (although the PHP code is much simpler):
$n = 0;
while (1) {
$s = "0e$n";
$h = md5($s);
if ($s == $h) break;
$n++;
}
echo "$s : $h\n";
Note: Use PHP's hash_equals() function and strict comparison operators to avoid this sort of vulnerability in your own code.
There is a programm from my University (IT-Securiy) where you have to try capturing "flags" by manipulating php or html code for example. We only see the code below and the programm runs on a website of them. So we need to somehow manipulate the url or something like this... but I really stuck on this one here:
<?php
require_once '_flags.php';
highlight_file(__FILE__);
if (isset($_GET['pw']) &&
md5($_GET['pw']) == '0e13371337133713371337133713371337') {
echo $doyouphp3_flag;
}
I know, that I have to submit a password by adding ...
?pw=...
... at the end of the url, but I just dont know what...
Is there any way to bypass the md5 function for example, because I dont think they want me to brutforce the password...
Hope someone can help me or at least give me a hint.
Marius
You just need to observe that 0e13371337133713371337133713371337 is a number, and it isn't a valid md5 hash.
Then you need to know how php loose comparison (with the == operator) involving numerical strings works. You can read that on the documentation:
If you compare a number with a string or the comparison involves
numerical strings, then each string is converted to a number and the
comparison performed numerically.
So, now you know that
var_dump('0' == '0e13371337133713371337133713371337'); // true
var_dump('0e123' == '0e13371337133713371337133713371337'); // true
var_dump('0e65165165165165' == '0e13371337133713371337133713371337'); // true
So, you just need to find a md5 hash that's also a number.
The md5 hash of 240610708 is 0e462097431906509019562988736854, and "0e13371337133713371337133713371337" == "0e462097431906509019562988736854" is true. So you can use that. But also QNKCDZO should works just fine.
What's the lesson here? That md5('240610708') == md5('QNKCDZO') is true and it's dangerous, and that you should use === instead of ==.
So if I do something like sha1($data) the result will be BLAHBLAH123. However if I do it again it will be BLAHAHS316. The same thing happens with md5. So my question is, what is a consistent way to hash values?
So like function($data) will return BLAHBLAHBLAH123 each time it is evaluated with the same $data parameter.
EDIT: I have a specific purpose in mind for this that isn't passwords so security isn't a concern.
EDIT: For example, md5($data) will not return BLAHBLAH every time, sometimes it'll return BLAHHHAL. I don't want that. I want it to return the same thing, BLAHBLAH everytime!
The output of a hashing operation will only change if the input has changed.
For example:
echo sha1( 'test' );
a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
If you wish it to change everytime, you could append a timestamp to the input:
echo sha1( 'test'.time() )
3d68b7693768f199623f31f820b1ba29b0a58769
Hashing function are deterministic (they would be useless if this was not the case).
In computer science, a deterministic algorithm is an algorithm which, given a particular input, will always produce the same output, with the underlying machine always passing through the same sequence of states.
Consider another (eg. time) input to the domain as in sha1(microtime() . $data) if you want 'different output'. I'm not sure how useful this will be in practice.
Password hash functions use a salt (randomly generated, stored separately) as additional input so the same plain-text password will result in a different stored hash value.
Hashing method - to give the same value, but not easy to predict or decode is what i think you are looking for.
You can use use a constant string val and do a hash of that string to get the same value always, if you want to change the value you can change the constant and get a different hash value
$constStr = "hashThis";
$hashWord = md5($constStr);
// it will return the same value always, as long as the constStr is the same
Two different input with same md5 or sha1 output?
That's possible but way to hard. Take a look at here: https://crypto.stackexchange.com/questions/1434/are-there-two-known-strings-which-have-the-same-md5-hash-value
The return value will change as long as your $data variable changes, you can't get same hashing value from different strings
the topic pretty much describes what we would like to accomplish.
a) start with a possible range of integers, for example, 1 to 10000.
b) take any md5 hash, run it thru this algo.
c) result that pops out will be an integer between 1 to 10000.
we are open to using another hashing method too.
the flow would ideally look like this:
string -> md5(string) -> algo(md5(string),range) -> resulting integer within range
is something like this possible?
final note: the range will always start with 1.
if you have an answer, feel free to post just the general idea, or if you so desire, php snippet works too :)
thanks!
Since MD5 (and SHA-1, etc.) will give you 128 bits of data (in PHP, you'll get it in hexadecimal string notation, so you need to convert it to an integer first). That number modulo 10000 will give you your integer.
Note however that many different hashes will convert to the same integer; this is unavoidable with any sort of conversion to your integer range, as the modulo operation essentially maps a larger set of numbers (in this case, 128 bits, that is numbers from 0 to 340,282,366,920,938,463,463,374,607,431,768,211,456) to a smaller set of numbers (less than 17 bits, numbers from 1 to 100,000).
since the range that we want will always start at 1, the following works great. all credit goes to Piskvor, as he was the one who provided the basic idea of how to go at this.
the code below seams to accomplish what we want. please chime in if this can be (not the code, its just for reference, but if the idea) improved at all. running the code below will result in 6305 / 10000 unique results. that in our case is good enough.
<?
$final=array();
$range=10000;
for($i=1;$i<=$range;$i++){
$string='this is my test string - attempt #'.$i;
echo 'initial string: '.$string.PHP_EOL;
$crc32=crc32($string);
echo 'crc32 of string: '.$crc32.PHP_EOL;
$postalgo=$crc32%$range;
echo 'post algo: '.$postalgo.PHP_EOL;
if(!in_array($postalgo,$final)){
$final[]=$postalgo;
}
}
echo 'unique results for '.($i-1).' attempts: '.count($final).PHP_EOL;
?>
enjoy!
I am having trouble with a complex script which sometimes (About 2 or 3 times while calulating about 90'000 values), generates a '-0' and writes it into the database. I suspect it's a string (The values which are calulated can result in integers, floats or strings.)*
Is there any PHP calculation which might result in a '-0'?
* = Oh, how I miss strong typing sometimes...
Rounding a negative number toward positive infinity, as ceil() does, can produce -0.
echo ceil(-.7);
// -0
The same result comes with, e.g., round(-.2).
Both of these will resolve to true:
(-0 == 0)
(ceil(-.7) == 0)
While these will resolve to true and false, respectively:
(-0 === 0)
(ceil(-.7) === 0)
Edit: An interesting (and implemented) rfc can be read here.
As Gurdas says, you can have your strong typing in the database. That aside, I don't know the answer to your question but I know how would I approach the problem.
The problem, as I understand it, is that you don't know in which cases you get the '-0', which is a valid floating point representation of 0, by the way. So you have to find in which cases you are getting that. I'd take one of two routes:
Use Xdebug, raise an error in the database insertion code when the value is '-0' to get a stack_trace with arguments (use xdebug.collect_params=1)
Create an empty string at the beginning of the script, populating it with all the operations and operands being done as they are, with the result and line. Afterwards, in the insertion clause add an if ($value == '-0') { print $string; }