 Hey folks today we're going to go over the ponable.kr level of collision. So we just did FD so now we're going to look at collision. So collision is a three-point problem. Does that mean it's three times as much more difficult than the FD problem? I have absolutely no idea these actually creating fair point systems for challenges is incredibly difficult so hey who knows. But we'll dive right in. So it says daddy told me something cool about MD5 hash collision today sounds interesting I want to do something like that. So SSH call at ponable.kr port 2222 password guest. So let's go in SSH there normally I'd have to type the guest password in but I have SSH multiplexing turned on here so it's actually nice it'll keep the connection open for me and that's why it was so fast. So when we get here same thing as before on the other one so we have a flag file that we desperately desperately want to access but we cannot access it it is permission denied. And so when we look call.c so we have a c file and we have the call binary which is setuid of call underscore pon which is exactly the user we need to be able to read the flag. So I've already downloaded these so my local machine let's look at call call.c so we have this unsigned long hash code of 21 dd09 ec a function called check password that sounds interesting a main function which takes in an argc and an argv vector and says if argc is less than two then print out the usage is argv zero then passcode so we should be able to verify that this is the case yep so we ran this binary we got usage is equal to dot slash call passcode so we need to pass in a passcode to pass this. Next the next check says if the string length of argv one is not equal to 20 then the passcode length should be 20 bytes so here we know okay we have to pass in something that's 20 bytes long the next thing says call check password on argv one check if that's equal to hash code if it is then output system bin cat flag return zero otherwise print out wrong passcode I hate c code that has this with the dangling clause here always always always use your curly braces all right even if it's only one line all right so we can try this we can just put out 101 and we can see ah passcode length should be 20 bytes so we can do 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 and it's a wrong passcode which makes sense because we just typed in something random but we know we got passed this first check and so it's now calling check password so now let's dive into this check password function so we can see it's a function that takes in a character pointer p returns an unsigned long so what does it do it first casts our character pointer p to an integer pointer so what this means is that it's going to still be pointed to the same memory location but now when you dereference that rather than talking about a single byte which is a character you'll actually be talking about four bytes we have an i a result zero and we're going to loop from i from zero to five i plus plus so we know this will execute five times it will say result plus equals ip bracket i so remember the super important thing to remember about c code is that ip so whenever you have a pointer ip bracket i is exactly the same thing as ip plus i which is pointer arithmetic dereference so these literally the bracket notation is syntactical sugar for this exact thing here so actually i may need to make this smaller okay so that should be good there so what this is doing so it's starting the result as zero and it's adding up and so it's incrementing over so remember we sent 20 bytes it's taking the first four bytes interpreting them as an integer adding that to result and then summing those all up such that the final result has to be equal to the hash code which is hex 21 dd 09 ec so one super easy way to think about this is thinking okay well why not just send all zeros right so we can send if we do something like so a the first thing is we have to remember okay we have to be inputting in here raw bytes so let's do this we're going to reset this we're going to have this be our c code and we will get in here okay so if we execute this program we need to execute raw bytes so one thing is hey this is the number this is our target number so the first thing is how do we get raw bytes into this program i actually love using python to do this so you can use python-c which says hey don't execute a python file but execute the command right here so we can build a one-liner so python-c what is the python program we want to do we want to print out so let's first uh we want x ec x 09 x dd x 21 so this is our target right this is what we want to be in this result variable here so why did i flip these bytes around that has to do with endian-ness so you should go look up the difference between little endian and big endian the idea is when you interpret four bytes which byte of those four bytes is the most significant byte so on little endian systems it's backwards of the way you'd expect it so this is just something you have to deal with and get used to so even though this is what we want in the hash code the string of bytes that we have in memory will have to be this way this is something you just get used to from doing many and many of these challenges so this is what we want if we do this this is not going to work why not well a we didn't input the program correctly but b it's going to tell us that it should be 20 bytes right and we only put in four bytes one two three four so we have to then say okay well let's just append so this is our final value this is what we want to be so why not just append let's say zero zero so we want no bytes times so we already have four we want 20 let's do 16 and so it still says passcode length should be 20 bytes so at this point we have to wonder hmm what's wrong with this nonsense either something's wrong with the challenge or something's wrong with our understanding of how this challenge works so actually for this i think it'd be nice to drop into gdb for gdb i actually use this jeff gdb gf extension which is a nice actually makes it a lot easier so i'm going to set a breakpoint on main and i'm going to run it with this so it's super cool you can use just run like this and now when we get here it's telling me it's it's at main here here's gf so this thing is super cool it's basically nice that it shows you it has where you are in the code so it automatically shows you where you're on the code it automatically shows you where you are in the stack trace the current stack although i frequent i hate that it goes down i always draw my stacks going up um but that may be something i'll fix later and then here it shows us the value inside all the registers so super you know useful stuff here so i'm right in the main function now i can step through this to kind of see about why it's going to um so why it's going to execute so what did just do um it is so when we step through here so it's going to call puts and it's going to say pass with code length should be 20 bytes so let's restart it back here it should show us hey next instruction so right before we got there we compared that and then we're going to do i see so it's um yeah so 14 hex 14 is going to be 20 like that there you go and so it's comparing that value with 20 but what is it comparing edi so if we go xs edi so the problem is if we look at the c code here it's actually compiled our string length check into i believe it's in line compiling that into this ad rep me all this fun stuff here but we can actually look because we know uh be due to the arg the due to the um calling convention the c deco calling convention that main the very first arguments of main will be at ebp so at ebp plus eight is the first argument of main i want this to be wide so we can actually see that okay so the three is interesting i'm not sure why it's three but that's okay oh it checks if it's less than two okay we have three argv vectors that's interesting but let's see so uh that means plus eight so three is our argv pointer here got our argc value this is going to be argc uh this value here is going to be a pointer to an array of pointers of argv so if we do x 20 y the x of oops that's not right of this guy that will give us a list of pointers so this if we're correct um this first one should give us so now what i'm going to do is i'm going to use s and i'm going to tell it interpret these as strings um okay that didn't work so okay so let's do go back here we'll do this so this very first string should be our our the string that we used our argv zero um yeah so this is perfect so this is the path that gdb used to execute this binary awesome so the second value then should be argv interesting ah well it's not a printable string that makes sense uh 20 x so how do we run this at ec and then this problem is this zero nine so this zero nine is not being considered as a so the string length here is going to be just one probably because this zero nine is probably white space if we did man asky we would see that the hex zero nine is a horizontal tab and so that may be what uh actually that's a good question let's see what is the byte sequence of so this is our argv one what's argv two because we didn't think to pass in two arguments it's dd 21 and if we go back to the how we've ran this dd 21 so super interesting stuff here so the zero nine we can't have any white space characters oh you know what we definitely can we'll just have to restart this like this and we'll print out our stack one more time and we'll see now we have two arguments so again it comes back to uh it comes back to single quotes here so the idea is because we had spaces and tabs in there the bashell was interpreting that as wanting to pass multiple arguments to this function but we want to prevent that so we can put everything in double quotes so we do that and then we do uh this is going to be our argv one now we can uh I think we can just print out string length of this we can see that it's d four interesting um xs so now if we do that and we look at it uh let's look at it as oh that's our environment pointer okay it makes sense so right this is argc this is argv so we actually didn't print out argv yet uh 21 s so yeah so this is going to be argv one this will be argv two we look at this and if we did this as a if we print out the string length of this it'll tell us we only have four bytes which is very surprising why because it looks like we printed out 20 200 bytes and so uh what actually happened here let's look at the bytes w 20 x so we can see we have ec09 dd 21 which is perfect that's exactly what we want in there but we have a zero what happened well when we ran this right we tried to add 16 zeros at the end but how does string length and c string c style strings uh indicate that it's the end of the string by using a null byte so in our input string we can't have a null byte because then string length will not think that we have 20 bytes so we have to make sure so this means that our initial thing of what we wanted to do is not uh correct all right let's pause okay so now that we know why we can't pass in zeros now the idea is okay so what do we want to pass in so we know we can get in the ec09 dd 21 so an easy thing to do would be what about 0 1 0 1 0 1 0 1 0 1 right those would be the smallest essentially the uh 0 1 0 1 0 1 0 1 0 1 so these would be the smallest oh these are in base 10 that's why that doesn't make sense okay 0 1 0 1 0 1 0 1 so these are going to be the smallest values here so if we do four of these four sets of four this will be this times four those will be added together for hex 0 4 0 4 0 4 0 4 and then finally the number that we want which is going to be ec uh now which will be 21 dd 0 9 ec so if we take um 21 dd 0 9 ec subtract 0 1 0 1 0 1 0 1 from it we see 20 dc 0 8 e b so now if we on our local copy so now we understood why that one didn't work now we'll say okay let's do it actually doesn't matter first or second or whatever because it's just being added together let's do a x 0 0 x 0 1 let's do 16 bytes of 0 1 followed by this string that we just put in and we remember we got to remember we've got to swap the order so this will be x e b x 0 8 x dc x 20 and ah we get length to be 20 bytes why because we forgot to double quote okay and it's telling us wrong passcode so that is interesting um so let's take this plus uh 0 4 0 4 0 4 0 4 ah that did not work okay why did that not work so so we have 21 dd 0 9 ec let's convert this to base 10 because i kind of don't trust scratch here and we our other number is 0 4 0 4 0 4 0 4 which we don't want there we want there 0 4 0 4 0 4 0 4 in space 16 so base 10 we'll copy this and now let's do everything in base 10 so we will do this number subtracted by this number switch it to base 10 so see we get a different number here so to be completely honest i don't know exactly why this happened but we can roll with it so we'll get here we need to print so the number now is 1 no e 8 we have to go back to front number 0 5 d 9 1 d boom and that's when we get the bin cat flag nosage file directory remember because i'm running this locally so if we take this command pop it on over to the server and which is being slow and i'm going to paste this command so now we're going to execute this we're going to call python we're going to pass that in and hopefully we will pass the hash code check so let's see if this is the case hit enter and we wait wait wait and there we go we get daddy i just mangled managed to create a hash collision so we copy paste that in and of course this is a little bit of a joke so now we can actually see when we go back here that this cool md5 hash collision is actually a bit of a lie that doesn't actually mean anything so it's not an md5 hash collision but it is you could think of it as the they're using a hash they're using addition essentially as a hash so we can do that and it should tell us that yes we are correct it may not do it i don't know i've already solved this so anyways that's it there we go we already authenticated this flag so thanks bye keep on hacking