Only in PHP though, since no other language would be stupid enough to implicitly decode HTTP POST variables into structured data types, thereby burdening all programmers by having to type-check incoming POST variables. :P
@@inx1819 Warnings don't throw exceptions... You would have to make a plugin/extension of some sorts or call an output checking function after every potentially dangerous call. Or checking for null on those hmacs...
That HMAC function definitely should have just thrown an error. It is incumbent on the programmer to know all possible states of a given algorithm, but if you look at the documentation null isn't even listed as a possible return value for hash_hmac. The fact that it's a cryptographic function, I almost have to wonder if that was put there intentionally. This definitely shows the importance of proper user-input sanitization.
Exactly, this function should throw exception for any parameter being null because doing so makes no sense at all. That does not give a good impression on PHP.
The fact that the null output on wrong input type is undocumented in official PHP docs is just terrible. Also, not erroring out when giving inputs of wrong type is not something PHP crypto functions are famous of. A good programmer must always check the types of inputs and also preferably the output type before continuing to keep the code safe.
@@apuherra8864 I get this and agree with you. But when you make a lib you can't expect people to read the source code (if available) and understand what flaws the code you have written can introduce in their code. As a software architect, I always ensure my teams code follow the Design by contract (DbC) principles. In this case, and it's a good one, hash_hmac should check Preconditions and Postconditions (arg types should be strings, not empty and result should not be a predictable result as a hashed \0 string or empty hashed managed string, etc...). This 2 or 3 lines of code could save systems from vulnerabilities and save the purpose of the dev using your lib trying to secure their systems or APIs. I often read or reverse engeneer dotnet framework code and I'm always happy to check that they follow the DbC pattern.
@@BonBaisers I mostly agree, but you _should_ change your "should" mindset to "must" in many places as per RFC 2119. Keeping "shoulds" when designing and not erroring out all the way back to where the error came on unintended circumstances just allows these hash_hmac types of bugs (or _may_ I say, undocumented features) to happen.
I think FB is using HHVM aka "Facebook HipHop" or so. But yeah their servers could possibly be C++, but the fact that Facebook's main preferable programming language was PHP proofs all these "PHP sucks" commenters wrong.
"Let's craft a cryptographic function which is very likely to be used in security contexts, and let's not fail when unexpected things are passed to us. What could go wrong." I'm livid.
I watched this video first a year ago, and now I am watching it again. I understand so much more but don’t feel like I could even get close to solving it. December 2020 I will come back and see what I think then.
Thanks for the super detailed walkthrough. I love how you concisely laid out your thought process and the various ideas you had or the checks to do, whether they worked or not for this instance.
this is the fourth vid i have watched by you and i have to say, youre a real mvp. I am interested very much in the stuff you cover on your channel, but not enough to really get into it or to justify dropping other hobbies for it. Thank you for more or less staying at the same niveau of needed knowledge for the most part. great content, keep it up ^^
Very good explanation, but as an habit I always check if a variable is null if the function may return null. That is a great example how it can have effects on live servers, not very visible at the beggining but if someone covers it your data and privacy is gone. Oh, also your money too.
I started with Php when I was a young teen... Misplacing the argument/parameters in methods is far too easy and common. Php is a language of inconsistencies, always important to triple check for that sort of thing.
You left out the Environment Elephant in the code room issue. On unixy servers that have multiple users, it is often easy to see the environment variable values of another user's processes. So if anyone else on that server can see your secret, they could possibly do more damage than just what that one script has access to. This is a known security issue that has popped up at times over the decades. In hardened OSs, users may be blocked from seeing the process of other users (and thus their environment), but that shouldn't be assumed in web code.
@@Omar-wm9kz I learned how php works and have worked with it on a daily basis, makes you pick up things almost instantly where otherwise you wouldn't even consider them
I've watched a few of your videos now and this is the first time I really understood what you were saying. I learned about Hashing algorithms in my SEC+ class. I just wanted to share my happiness for knowing like 80% of what you were saying.
So... The vulnerability was actually 2 dumb and exploitable vulnerabilities... That hash_hmac function gives a WARNING when fed an array and returns a NULL?? also... the secret can be NULL... (facepalm). What gives? What is the benefit of having a NULL secret? Please, let me know, I'm puzzled.
Maybe it inherited the old minute man nuke doctrine's 00000000 input? Or more seriously it might be a feature for the unit testing framework of the hmac implementation, and it's got hard coded outputs that return sooner than when a secret exists. I doubt oracle has such a unit testing framework for php though, it's one of the buggiest and least consistent languages out there. The most likely scenario is that it just doesn't care if the input is null, and processes it as if it were 0.
Man you are doing an amazing job at these kind of videos ! Really enjoyed this one ! Keep making similiar kinds of videos . Getting into the nooks-n-crooks of things is what I always wanted !
Love that. Back when I was young, I did such thinking all over the day and found so many critical bugs in different servers. I somehow even managed to get into a MySQL backend that wasn't even secured with a login, so with little coding experience and never hearing of PhpMyAdmin, I had control over sensitive data. Of course I did nothing bad.. it was a gaming server (CS 1.6) and I just played around with my own stats to see what will happend and get some experience about PMA. Back then I was so good at playing that the admins thought that I am cheating (the server had a mod called "Uwc3 Mod" in which you could get a skill to steal money from your enemies.. combined with experience and sounds from the enemies, predicted shoots trought the walls after hearing small steps and seeing that I get money, would make me KNOW that an enemy is there.. of course this looks like I can see trough walls) so I got banned from the server. While looking at the PMA I also cound a banned users list.. so I tried out if I get unbanned when I remove my self from there.. was funny having such might! But like Spiderman said.. with big might comes big responsibility.
Abdillah Muhamad String-Equals stops as soon as a difference is found. So (simplified) you put in a hmac beginning with an 'a' and measure the time the script takes to run, then you do it with a 'b', 'c', .. - for one input the string-comparison will take slightly longer because it has to check the second letter as well. That will be your first letter. Even if you try every start-character 1000x times, it would still only take (256 / 4 = 64'000) requests to the server, which is easily feasible within minutes. In reality it's a bit harder because string-equals usually checks more than one character at a time. And if you want to defend against it: look up constant time string equality checks.
sorry but this sounds like a bs. You would need PERFECTLY SAME network and server conditions on EVERY request to even have a chance at measuring execution time. I dont even think you could measure difference between php reaching second or third char
macccu well, you can measure it against your server ping, so then you don't need the same conditions because you have a standard measurement. And you could just submit more detailed variables, ie have the first 3 digits vary and then you should have a slight difference in the vicinity of the correct string, so you have your first 2 digits, rinse and repeat to get the rest.
honkatatonka I was thinking the same thing. Wow. I even checked the docs and they didn't mention returning null sometimes. I'm shocked in the nerdiest of ways...
oh boi if you think that's bad, go look up "Heartbleed" which was written in C. Doesn't really matter the language, most common errors in programming are almost always caused by human error.
Well this particular error is caused by weak typing and not compiling. You can of course make horrible mistakes in any languages, but those two things really don't help you in preventing mistakes.
honkatatonka true. hash_hmac is just bad in this case. It should never return NULL where you expect it to get a hash. Input type violation should result in a fatal error, not a warning.
That last line is so obvious that anyone can see. I think the problem was meant for you to find the non-trivial bug, the last line only for getting the content of flag file on the machine (if it was in CTF).
Great video, i got to the same part as you at the end but i couldn't figure out what kind of input would change the type, and I got lazy and just watched the video instead
I actually got as far as determining that the goal here would be to set a value for nonce that would allow you to compute the hmac that made the !== statement true, but I'm not a programmer so wasn't able to determine on my own what to set the nonce to. I was really big into studying the security of the xbox 360 and learning how all the exploits worked so that definitely helped me out here.
Everyone is saying how PHP sucks, but probably haven’t written anything serious in it. It’s a good language if you know how to use it, just like any other language.
For someone who is just starting off with programming and only knows the anatomy of code so far, this was oddly logical :o :) One piece of feedback: My eyes didn't like the sudden transition from dark to bright white backgrounds :)
An other possibility is PHP is configured so all errors are fatal. If the PHP do not have an error handler, it usually display them with the scope variables. That would expose the value of $secret, allowing you to forge any signature to futur requests.
Huh? Usually when PHP errors for me it just goes 500, not showing any data. If theres any data shown it's in the error.log, which of course someone from outside shouldn't be able to access.
In PHP, === is often optional, and quite often, == is what you want, since the type juggling it does generally makes sense, and are often useful. In JS, === is pretty much mandatory, since it's type juggling skills are about as good as someone driving after downing 2 cases of beer.
@SlowSunsetVibes Not sure where you get your information, but you are incorrect. PHP 8 has type juggling. It is a core language feature. Removing it would break nearly every codebase in existence. The difference between PHP and JS is that PHP type juggling makes sense. Comparisons of different types are very common. I use == most the time, unless I have a specific reason I need to check explicitly, such as a function that can return a number or false, and they mean different things. For instance, checking if a string contains a substring, it could return 0 or higher, or false. 0 means beginning of string, false means not found. If type juggling didn't exist though, doing simple things like compare numbers would require mass amounts of extra code. The vast majority of time, the == operator works as you would expect. In Javascript, the comparisons are so horrible, one has to wonder if they are completely random. They make absolutely no sense at all, and results in mass amount of bugs, which is why it is not used. Honestly they SHOULD remove it.
9:47 i had to get here and get reminded that you can to client-side php arrays, and then... i bet that if you supply an empty array, isset == true, but then output of the hash functions is either predictable, or a predictable gibberish (for example it spits out null or false or something like that), making all the rest of the checks "pass" == get skipped, basically
I expected a completely different approach to that challenge when I reviewed the code in the beginning. I guessed that the challenge description contains an example invocation of that PHP script *without* the optional nonce, so you know the HMAC for one specific safe string like "www.google.com". In that case, you could input the safe string as nonce, and the new nonce-specific secret will be the public HMAC for the safe string, which enables you to calculate the HMAC for any input you want.
A lot of similar bugs would simply never exist, if PHP would use strong typing. It is really annoying that you can't even rely on the equal sign. What would be the best practice to bulletproof this code? - check agaings NULL secret -> checks against this specific bug, others may still exist. - check every user supplied variable to be the valid type, i.e. not an array and are string? - I think the hmac function should die. It is a security function, I can't imagine a worse outcome of a hash function than it is always returns the same value regardless of the input data. Is this behavior considered bug by you? - By the way, passing directly a formally unchecked user input to exec also does not seem to be the smartest thing either. :-)
These security issues have nothing to do with strong typing. Many languages have weak typing without creating security issues because of it. The problem is that PHP handles so many things so extremely dumb and counterproductive.
Yes, hash_hmac should have aborted; NULL isn't even a documented return value for it, only that the arguments should be strings. What is documented is that its return value violates the described type if the algorithm is unknown. And of course that has changed; there may be code out there that used to produce hashes but now always produces FALSE.
Damn that! When I first saw this I didn't couldn't understand shit. But, today I saw it again and now that I understand it, I wanna explore more. Thanks man! You inspire me to keep going
Took me a bit, but I effectively ended up following the same path as LiveOverflow. My first thought was to try and force an integer or float type into the nonce, but that wasn't giving the results. Then I remembered that POST parameters can be arrays, and the rest followed. One line fix, by the way: $nonce = "".$_POST['nonce'];
Amazing video man i have been learning a lot in this lock down this is all because of you and John Thanks a lot for making videos and spreading knowledge amazing work . Lots of respect to all those who share knowledge.....
if you could capture just one valid message from a request, then you can break this a different way. example: assume you capture a request where the host = 'www.example.com' and the hmac = 'foobar' (just ignore the invalidity for simplicity). now you can predict the secret: if you use 'www.example.com' as the nonce then you know the final secret is 'foobar' and can hash your payload with that
I clicked only after you mentioned about the array input trick. It's not even a thing in languages I usually use. They just throw uncaught exceptions and crash.
I am programming PHP at the moment. Coming from C++ the security of the code is lifted to a whole new level when programming PHP. These are always the unpredictable things in the language, C++ is much more straight forward in my opinion in that regard.
There is no salting value to generate a value to test against the hash issued, no filter_var on the input and no white listing and the exec function can be exploited.
I had paused the video at the beginning and came up with a completely different answer: the !== likely stops upon the first mismatching character, leading to a timing side-channel. (The time it takes for the server to reject your request increases with the number of correct characters in the submitted HMAC, so characters in the correct HMAC can be learned one-at-a-time by seeing which next character results in the highest average response time.)
First I thought, you could bruteforce the nonce, just try it until you get from the server something else than 403. But then... WTF PHP Why would you return NULL here? That's completely unexpected. If I use a hash function, I'd expect it to return a hash. Hash functions do nothing else, what ever you give them, they return a hash. And that hash would be as you expect a hash to be. Which is certainly anything else than NULL. Of course you can't just cast an array to a string, that's a type error. But the function should then either set the second parameter to "0" (lazy but still not breaking because here the nonce is always "0" and you still get a proper hash) - or throw a proper exception and die. Once again, sloppy designed build-in functions, that behave unexpected.
The problem was that the secret was known by the attacker. If it always sets it to "0" that's still a problem because you could use "0" as the secret in your own HMAC (the security of HMAC comes from the secret being unknown to anybody except for the authorized user). It should hard abort when it sees that because obviously a) it wouldn't work in the 1st place and b) it's probably an attacker because you should know what to put in your variables.
The host parameter is not sanitized. An attacker can pass extra commands to the exec function and cause them to be executed at the same privilege level as the php script.
It's like php is developed specially for hackers. Checking the type and value of a user input before passing it into a function is good practice for any programming language though.
@@RedStone576 I actually started working on this yesterday! Still in the designing phase though. I will probably leave it to be a several-year-long project; I don't have the skills yet to write interpreters
Note to self.. Check types of incoming information, not just that it exists.
Note to self.. Do that too
That is called type checking, where have you heard of this before?
Just real escape sting chill
「ᗴᔕ」- EuroSplits Offical Clan Channel
real escape 2 mysql i, couldn't even get escaping right after two attempts.
Only in PHP though, since no other language would be stupid enough to implicitly decode HTTP POST variables into structured data types, thereby burdening all programmers by having to type-check incoming POST variables. :P
Fun fact: in PHP 8 these warnings for incorrect types passed to functions kill the script with an error instead
AT LAST! I've waited through 5 major versions of PHP for them to get rid of this truly awful excuse for an error system.
Ah that's why so much PHP code isn't compatible with PHP 8 :D
@@TheStiepenThat also why PHP8 is actually a useful programing language where you don't have to worry about this type of things
this is why every production php application should hard crash on warnings
try{...} catch (...) {echo "Error!"}; ???????????
@@inx1819 Warnings don't throw exceptions...
You would have to make a plugin/extension of some sorts or call an output checking function after every potentially dangerous call.
Or checking for null on those hmacs...
@@rogercruz1547 Easy to get this setup with set_error_handler and having that handler throw an ErrorException based on what error number is triggered.
Speaking as a PHP developer of many many years.... warnings are a CURSE! ........ PHP is a curse
That HMAC function definitely should have just thrown an error. It is incumbent on the programmer to know all possible states of a given algorithm, but if you look at the documentation null isn't even listed as a possible return value for hash_hmac. The fact that it's a cryptographic function, I almost have to wonder if that was put there intentionally. This definitely shows the importance of proper user-input sanitization.
Exactly, this function should throw exception for any parameter being null because doing so makes no sense at all. That does not give a good impression on PHP.
The fact that the null output on wrong input type is undocumented in official PHP docs is just terrible. Also, not erroring out when giving inputs of wrong type is not something PHP crypto functions are famous of. A good programmer must always check the types of inputs and also preferably the output type before continuing to keep the code safe.
@@apuherra8864 I get this and agree with you. But when you make a lib you can't expect people to read the source code (if available) and understand what flaws the code you have written can introduce in their code. As a software architect, I always ensure my teams code follow the Design by contract (DbC) principles. In this case, and it's a good one, hash_hmac should check Preconditions and Postconditions (arg types should be strings, not empty and result should not be a predictable result as a hashed \0 string or empty hashed managed string, etc...). This 2 or 3 lines of code could save systems from vulnerabilities and save the purpose of the dev using your lib trying to secure their systems or APIs. I often read or reverse engeneer dotnet framework code and I'm always happy to check that they follow the DbC pattern.
@@BonBaisers I mostly agree, but you _should_ change your "should" mindset to "must" in many places as per RFC 2119. Keeping "shoulds" when designing and not erroring out all the way back to where the error came on unintended circumstances just allows these hash_hmac types of bugs (or _may_ I say, undocumented features) to happen.
# Never trust parameters from the scary internet, only allow the white list through.
The deadly bug is PHP itself.
Your face seems to be a bigger bug.
Every time I hear of PHP I hear about all these attacks and insecurities. It makes me nervous
Meh, that's bullshit. PHP is the most used web language.
Even Facebook is made with PHP.
MusicAddiction Although Facebook uses their own modified version of PHP, it is the same. Much of their backend servers are implemented in C++ anyways
I think FB is using HHVM aka "Facebook HipHop" or so. But yeah their servers could possibly be C++, but the fact that Facebook's main preferable programming language was PHP proofs all these "PHP sucks" commenters wrong.
"Let's craft a cryptographic function which is very likely to be used in security contexts, and let's not fail when unexpected things are passed to us. What could go wrong." I'm livid.
I watched this video first a year ago, and now I am watching it again. I understand so much more but don’t feel like I could even get close to solving it. December 2020 I will come back and see what I think then.
am waiting for ur comment and i will come in december 2021 cuz itz my firsr time here.
so what happened? did you get close to solving it after 4 years?
@@ZoMbiE4CoBRA you actually reminded him 🤣🤣🤣
Thanks for the super detailed walkthrough. I love how you concisely laid out your thought process and the various ideas you had or the checks to do, whether they worked or not for this instance.
I originally thought the "deadly bug" was the use of PHP.
I can't code, but you explain well enough that I'm actually beginning to understand bits and pieces and patterns.
this is the fourth vid i have watched by you and i have to say, youre a real mvp.
I am interested very much in the stuff you cover on your channel, but not enough to really get into it or to justify dropping other hobbies for it.
Thank you for more or less staying at the same niveau of needed knowledge for the most part. great content, keep it up ^^
"Stupid brain, so unreliable"
Story of my life....
This video after long time reminded me of what amount fun we can have. Thanks for the great video.
I don't know anything about coding and UA-cam recommended this video. I have no idea what was talked about in this video but keep it up, good stuff.
Very good explanation, but as an habit I always check if a variable is null if the function may return null. That is a great example how it can have effects on live servers, not very visible at the beggining but if someone covers it your data and privacy is gone.
Oh, also your money too.
I started with Php when I was a young teen... Misplacing the argument/parameters in methods is far too easy and common. Php is a language of inconsistencies, always important to triple check for that sort of thing.
You left out the Environment Elephant in the code room issue. On unixy servers that have multiple users, it is often easy to see the environment variable values of another user's processes. So if anyone else on that server can see your secret, they could possibly do more damage than just what that one script has access to. This is a known security issue that has popped up at times over the decades.
In hardened OSs, users may be blocked from seeing the process of other users (and thus their environment), but that shouldn't be assumed in web code.
whatching php bugs is just like watching wheels turn. It never ends.
I honestly had no idea you could pass an array like that
I watched this video when it came out.
2 years later I am a php developer and I watched it again. It felt completely different :)
why and how?
@@Omar-wm9kz I learned how php works and have worked with it on a daily basis, makes you pick up things almost instantly where otherwise you wouldn't even consider them
Thankyou! as someone trying teach themselves code, your explanations were really informative.
I’m surprised you didn’t at least mention the timing unsafe hash comparison. PHP has a built in hash_equals() function to mitigate...
Great thinking. In the end it's all so obvious!
There must be so many vulnerabilities in my code...
I'm worried I have a framework written in this thing... and I'm not sure the hmac bullshittery is documented in the phpsadness page
why does youtube not recommend people like you... why do i have to search so hard!!!
thumbs up for using redstar os. ;)
I've watched a few of your videos now and this is the first time I really understood what you were saying. I learned about Hashing algorithms in my SEC+ class. I just wanted to share my happiness for knowing like 80% of what you were saying.
So... The vulnerability was actually 2 dumb and exploitable vulnerabilities... That hash_hmac function gives a WARNING when fed an array and returns a NULL?? also... the secret can be NULL... (facepalm). What gives? What is the benefit of having a NULL secret? Please, let me know, I'm puzzled.
Maybe it inherited the old minute man nuke doctrine's 00000000 input? Or more seriously it might be a feature for the unit testing framework of the hmac implementation, and it's got hard coded outputs that return sooner than when a secret exists. I doubt oracle has such a unit testing framework for php though, it's one of the buggiest and least consistent languages out there. The most likely scenario is that it just doesn't care if the input is null, and processes it as if it were 0.
It's so that the secret is predictable, so the last if statement would not run and stop the program
RedMikePumpkin Yeah, I got it. I was asking about what were the developers thinking when they coded the function.
@@Otakutaru The core php devs, thinking while coding? That's a new one
NULL == 0 so the secret is really just 0, which makes sense to work.
Man you are doing an amazing job at these kind of videos ! Really enjoyed this one ! Keep making similiar kinds of videos . Getting into the nooks-n-crooks of things is what I always wanted !
Uncovering the deadly bug was truly exciting !
Love that. Back when I was young, I did such thinking all over the day and found so many critical bugs in different servers. I somehow even managed to get into a MySQL backend that wasn't even secured with a login, so with little coding experience and never hearing of PhpMyAdmin, I had control over sensitive data. Of course I did nothing bad.. it was a gaming server (CS 1.6) and I just played around with my own stats to see what will happend and get some experience about PMA. Back then I was so good at playing that the admins thought that I am cheating (the server had a mod called "Uwc3 Mod" in which you could get a skill to steal money from your enemies.. combined with experience and sounds from the enemies, predicted shoots trought the walls after hearing small steps and seeing that I get money, would make me KNOW that an enemy is there.. of course this looks like I can see trough walls) so I got banned from the server.
While looking at the PMA I also cound a banned users list.. so I tried out if I get unbanned when I remove my self from there.. was funny having such might! But like Spiderman said.. with big might comes big responsibility.
Nice videos. I enjoy them (even though I already know a lot of the stuff). Your way of thinking matches a lot of how I think when looking at code.
Thanks to the subtitles i can underestand all ty liveoverflow
Also, timing attack on "!==" might be possible.
how ?
Abdillah Muhamad String-Equals stops as soon as a difference is found. So (simplified) you put in a hmac beginning with an 'a' and measure the time the script takes to run, then you do it with a 'b', 'c',
.. - for one input the string-comparison will take slightly longer because it has to check the second letter as well. That will be your first letter.
Even if you try every start-character 1000x times, it would still only take (256 / 4 = 64'000) requests to the server, which is easily feasible within minutes.
In reality it's a bit harder because string-equals usually checks more than one character at a time.
And if you want to defend against it: look up constant time string equality checks.
Fly - Thanks, I learned something useful today.
sorry but this sounds like a bs. You would need PERFECTLY SAME network and server conditions on EVERY request to even have a chance at measuring execution time. I dont even think you could measure difference between php reaching second or third char
macccu well, you can measure it against your server ping, so then you don't need the same conditions because you have a standard measurement.
And you could just submit more detailed variables, ie have the first 3 digits vary and then you should have a slight difference in the vicinity of the correct string, so you have your first 2 digits, rinse and repeat to get the rest.
Every single video on this channel is amazing and 100% informative. .....
I love this channel....
This is the first time I understand why people dislike PHP ... cheesus. EDIT: is this hash_hmac part of the core lib or some 3rd party screw up?
part of core php.net/manual/en/function.hash-hmac.php
honkatatonka I was thinking the same thing. Wow. I even checked the docs and they didn't mention returning null sometimes. I'm shocked in the nerdiest of ways...
honkatatonka wow this is a new type of language
@@DeusEx3 www.php.net/manual/en/function.hash-hmac.php#122657 remember to read comments. PHP documentation is notoriously incomplete.
It's php, that's your deadly bug right there.
oh boi if you think that's bad, go look up "Heartbleed" which was written in C. Doesn't really matter the language, most common errors in programming are almost always caused by human error.
KamiKagutsuchi I thought the same thing haha
Come on, C is so barebones. But having such a loose unintuitive API as hash_hmac is just bad
Well this particular error is caused by weak typing and not compiling. You can of course make horrible mistakes in any languages, but those two things really don't help you in preventing mistakes.
honkatatonka true. hash_hmac is just bad in this case. It should never return NULL where you expect it to get a hash. Input type violation should result in a fatal error, not a warning.
On top of what you found the last line itself is a deadly bug, Passing data directly into exec opens a door for all kinds of injections.
That last line is so obvious that anyone can see. I think the problem was meant for you to find the non-trivial bug, the last line only for getting the content of flag file on the machine (if it was in CTF).
obv the bug is
Most PHP frameworks turn warnings/notices/errors into exceptions so that will mitigate these sort of issues.
the deadly bug is the whole PHP language
Literally every word went above my head.....
Still watched the whole video xD
Great video, i got to the same part as you at the end but i couldn't figure out what kind of input would change the type, and I got lazy and just watched the video instead
I actually got as far as determining that the goal here would be to set a value for nonce that would allow you to compute the hmac that made the !== statement true, but I'm not a programmer so wasn't able to determine on my own what to set the nonce to. I was really big into studying the security of the xbox 360 and learning how all the exploits worked so that definitely helped me out here.
Everyone is saying how PHP sucks, but probably haven’t written anything serious in it. It’s a good language if you know how to use it, just like any other language.
or the last time they used it was PHP 4, It's like bitching about how shit Windows XP _currently_ is lol.
This was such a good video! Please make more like this. You've earned a loyal subscriber :)
The deadly bug is that the developer uses PHP:D
Awesome video! Really made me understand better how to approach something like this.
For someone who is just starting off with programming and only knows the anatomy of code so far, this was oddly logical :o :)
One piece of feedback: My eyes didn't like the sudden transition from dark to bright white backgrounds :)
PHP team, please update your documentation.
Inform about returning null value.
We developers heavily trust your documentation.
An other possibility is PHP is configured so all errors are fatal. If the PHP do not have an error handler, it usually display them with the scope variables. That would expose the value of $secret, allowing you to forge any signature to futur requests.
Huh? Usually when PHP errors for me it just goes 500, not showing any data. If theres any data shown it's in the error.log, which of course someone from outside shouldn't be able to access.
It's a PHP configuration. Some people forget "development" mode that'll format the errors and exceptions into a HTML response
display_errors = On
In PHP, === is often optional, and quite often, == is what you want, since the type juggling it does generally makes sense, and are often useful. In JS, === is pretty much mandatory, since it's type juggling skills are about as good as someone driving after downing 2 cases of beer.
@SlowSunsetVibes Not sure where you get your information, but you are incorrect. PHP 8 has type juggling. It is a core language feature. Removing it would break nearly every codebase in existence. The difference between PHP and JS is that PHP type juggling makes sense. Comparisons of different types are very common. I use == most the time, unless I have a specific reason I need to check explicitly, such as a function that can return a number or false, and they mean different things. For instance, checking if a string contains a substring, it could return 0 or higher, or false. 0 means beginning of string, false means not found. If type juggling didn't exist though, doing simple things like compare numbers would require mass amounts of extra code. The vast majority of time, the == operator works as you would expect. In Javascript, the comparisons are so horrible, one has to wonder if they are completely random. They make absolutely no sense at all, and results in mass amount of bugs, which is why it is not used. Honestly they SHOULD remove it.
PHP is always so full of surprises!
I love how you explain it. :D
PHP is the fractal that keeps on giving.
Thanks for another awesome video!! This channel gets me pumped to capture some flags :D
9:47 i had to get here and get reminded that you can to client-side php arrays, and then... i bet that if you supply an empty array, isset == true, but then output of the hash functions is either predictable, or a predictable gibberish (for example it spits out null or false or something like that), making all the rest of the checks "pass" == get skipped, basically
Bro I am missing your videos 😭😭.. keep upload this type of videos
This is absolutely awesome. Thank you for making this.
I understood none of that, but have the feeling that I learned something.
I never knew PHP could be so much fun! Terrfic vid!
how did i not know about this channel until now?!
I expected a completely different approach to that challenge when I reviewed the code in the beginning. I guessed that the challenge description contains an example invocation of that PHP script *without* the optional nonce, so you know the HMAC for one specific safe string like "www.google.com". In that case, you could input the safe string as nonce, and the new nonce-specific secret will be the public HMAC for the safe string, which enables you to calculate the HMAC for any input you want.
more of these challenges please
A lot of similar bugs would simply never exist, if PHP would use strong typing. It is really annoying that you can't even rely on the equal sign.
What would be the best practice to bulletproof this code?
- check agaings NULL secret -> checks against this specific bug, others may still exist.
- check every user supplied variable to be the valid type, i.e. not an array and are string?
- I think the hmac function should die. It is a security function, I can't imagine a worse outcome of a hash function than it is always returns the same value regardless of the input data. Is this behavior considered bug by you?
- By the way, passing directly a formally unchecked user input to exec also does not seem to be the smartest thing either. :-)
These security issues have nothing to do with strong typing. Many languages have weak typing without creating security issues because of it. The problem is that PHP handles so many things so extremely dumb and counterproductive.
Yes. Imagine the idea of giving just a warning after noticing that a cryptographic function got an input it can't do absolutely anything with.
just make json out of post data always before using it in hmac and thats it. thats how i do it
Use `filter_input(INPUT_POST, 'nonce')`, this enforces the parameter types
Yes, hash_hmac should have aborted; NULL isn't even a documented return value for it, only that the arguments should be strings. What is documented is that its return value violates the described type if the algorithm is unknown. And of course that has changed; there may be code out there that used to produce hashes but now always produces FALSE.
The missing curly brackets is it first thing that caught my eye.
In some programming languages if statements don't require brackets if it is only executing one function, or one line of code.
@@christophermc2 I know but it can be easy to make a mistake that is not easily spotted that leads to unexpected behavior.
Damn that! When I first saw this I didn't couldn't understand shit. But, today I saw it again and now that I understand it, I wanna explore more. Thanks man! You inspire me to keep going
Took me a bit, but I effectively ended up following the same path as LiveOverflow. My first thought was to try and force an integer or float type into the nonce, but that wasn't giving the results. Then I remembered that POST parameters can be arrays, and the rest followed. One line fix, by the way: $nonce = "".$_POST['nonce'];
Amazing video man i have been learning a lot in this lock down this is all because of you and John Thanks a lot for making videos and spreading knowledge amazing work . Lots of respect to all those who share knowledge.....
Your logics are amazing!
if you could capture just one valid message from a request, then you can break this a different way. example: assume you capture a request where the host = 'www.example.com' and the hmac = 'foobar' (just ignore the invalidity for simplicity). now you can predict the secret: if you use 'www.example.com' as the nonce then you know the final secret is 'foobar' and can hash your payload with that
I clicked only after you mentioned about the array input trick. It's not even a thing in languages I usually use. They just throw uncaught exceptions and crash.
This was nice, I thought that too, but only when I ran out of options
I am programming PHP at the moment.
Coming from C++ the security of the code is lifted to a whole new level when programming PHP. These are always the unpredictable things in the language, C++ is much more straight forward in my opinion in that regard.
There is no salting value to generate a value to test against the hash issued, no filter_var on the input and no white listing and the exec function can be exploited.
the biggest bug is that input for the exec was not escaped at all
I had paused the video at the beginning and came up with a completely different answer: the !== likely stops upon the first mismatching character, leading to a timing side-channel. (The time it takes for the server to reject your request increases with the number of correct characters in the submitted HMAC, so characters in the correct HMAC can be learned one-at-a-time by seeing which next character results in the highest average response time.)
Maybe if you had unbelievably stable ping to the server.
@@zjohnson1632 As long as the network delay is independent of the data being sent, it will cancel itself out with a large enough sample size.
I subscribed instantly after the logo animation.
Pretty good. Thank you for sharing your knowledge
Hey, Please make more "dive into my brain" videos. It's really helpful for beginners to build a reverse engineer mindset.
In Perl this is so common, I would've checked it first.
Who does not love dynamically typed languages!
I really liked this video topic and format. Thanks!
First I thought, you could bruteforce the nonce, just try it until you get from the server something else than 403.
But then...
WTF PHP Why would you return NULL here? That's completely unexpected. If I use a hash function, I'd expect it to return a hash. Hash functions do nothing else, what ever you give them, they return a hash. And that hash would be as you expect a hash to be. Which is certainly anything else than NULL. Of course you can't just cast an array to a string, that's a type error. But the function should then either set the second parameter to "0" (lazy but still not breaking because here the nonce is always "0" and you still get a proper hash) - or throw a proper exception and die.
Once again, sloppy designed build-in functions, that behave unexpected.
The problem was that the secret was known by the attacker. If it always sets it to "0" that's still a problem because you could use "0" as the secret in your own HMAC (the security of HMAC comes from the secret being unknown to anybody except for the authorized user). It should hard abort when it sees that because obviously a) it wouldn't work in the 1st place and b) it's probably an attacker because you should know what to put in your variables.
"bruteforce the nonce" is a strange sentence out of context
Love this kind of video and would like to see more like it!
Excellent explanation. You deserve my subscribe.
It is just entertaining to watch even though i don't know what the hell he is even talking about.
The host parameter is not sanitized. An attacker can pass extra commands to the exec function and cause them to be executed at the same privilege level as the php script.
Root insurance car ad comes on: Hello, we are root
Me: 🙄😯 how did you get root
At 8:15 as you talk the bug was clear to me, isset could be also null :) then secret will be null and thats the exploitation
Thanks TIL you can pass an array as a POST value, nice
Oh yes, little bobby tables, we call him!
It's like php is developed specially for hackers. Checking the type and value of a user input before passing it into a function is good practice for any programming language though.
well normally that shouldn't be an issue, you should always validate user input, i learned that the hard way.
learned a lot , thanks for your video
Arrays was my first thought :)
it s so simple sir
and i like you
we love you too buddy!
Great video ... thanks man for sharing
I'm gonna make my own strict version of PHP now
any updates?
@@RedStone576 I actually started working on this yesterday! Still in the designing phase though. I will probably leave it to be a several-year-long project; I don't have the skills yet to write interpreters
My guess formatted as type: < LIBRARY : Shell view! >
>> python3 phpRunner.py
Which PHP file?
>>> challenge.php
Executing...
Complete! Output:
Console output:
SyntaxError: Expected { on line 10
this is the fifth time i watched this, and I finally get it