 Hey everyone, my name is John Hammond, this is Pico CTF 2017, and the challenge is guess the number. Challenge prompt is just a simple number guessing game, how hard could it be? Give us a binary and some source code, and a remote connection that we could go to if we needed to. So let's go ahead and download these here, let's check out what we've got to work with, just another binary and some C source code, and let's check out the hints. It says, what is the program doing with your input number, and STRTOL checks for overflow, but it does allow negative numbers. Okay, so for a little bit of context, let's take a look at what we're working with. We've got some C source code. It gives us little T's at the top of your comment, how well do you know your numbers? And a function win that will give us a shell, okay? So that's clearly what we need to do, get the flag and win. And our main function creates a variable called val with data type UNT PTRT. So I haven't seen this before, so I went ahead and googled it, and it is just kind of as we would expect, an unsigned integer, hence UNT, that is capable of storing a pointer. Okay, I was just curious in that it's an unsigned integer, okay? That's fine. Reads in from a buffer, et cetera, thinking of a number, can you guess it? Enter your number, and it looks like it's wanting 32, 32 bytes here, 32 bits, I suppose, to get that 32 bytes for the buffer. And then it will convert it to a long, with string too long, STRTOL, checking for an overflow, because STRTOL will only allow so many bytes for that number or for val. So it says you entered it, let's see if it was right. And it does this operation with val that's a binary operation by shifting it to the right for position. So we can take a look at that in Python just to showcase it. And then it tries to execute that number, that value that we pass in, it literally just runs it as if it were code. So maybe we could take advantage of that to actually run the win function and execute where that address is in memory. So let's go ahead and take a look at that. If I were to check out the binary, check out the symbols in there, we can see we have this win function right over here available at this hex address. So let's take idle, let's just work in Python here. Let's get that number hexadecimal here. That's it in decimal, whatever, not a big deal. But we want to know what that is. Again, if we were to shift it to four positions, and I'll show you that in binary. First of all, let's just get a binary number like 0, 0, 0, 0 and 1, 1, 1, 1. So that's 15, whatever. And then can I see that in binary? Okay, that moves it just fine. Because the zeroes in the front don't particularly matter. Let's go ahead and add them at the end. So now we've got a bigger number because the zeroes will stay in place, and that's 240. Great. So let's go ahead and shift that binary number four places, that's shifting to the right four places. So this one will move, and then we'll get a zero over here. The one will move again, get a zero back over there. Ones will move the right again, obviously four times until this happens over and over again. And that will end up getting us the 15 that we saw earlier, because we shifted it now. If I took the bin of this, you can see that, okay, the zeroes have now translated to the very, very front before the B representation in binary, and then it's as if they weren't even there, just like when we looked at them before at the very start, it would, okay, now it considers it to be 1, 1, 1, 1 and 15 in decimal. So that's the binary shift in the right case. It's literally just moving the numbers to the right and wrapping them around. So in our case, when we're working with this hexadecimal value, and it shifted to the right, we would get that, whatever. But if this is the value that we want, if that's the hexadecimal address that we want to have in memory, we would have to see what it is shifted to the left. So when we supply it, and they shift it to the right, it is the value that we want. Great. So it's this decimal number, okay. And if we wanted to go ahead and submit that, we could try it. Let's go over there. Let's run a guess num, market is executable to run the program. And if I paste it in, you can say, oh, hey, you entered this number, which is not that number. And see if it would write, it's like false because it can't get anything at that address, that address, whatever. So okay, that is an error. But it's strange that this is the number that we're seeing. Why is that? If we Google this number, you can find that this is the interesting fun fact, 8th Merceni prime, but it's also the highest number in computing. It's the maximum positive value for a 32-bit signed binary integer in computing. So keep track that this is assigned, and that that means it's either positive or negative. However, we know that we are working with an unsigned value, our val function, and that means that, okay, we're only getting positive numbers here. But our hints told us that strl or string to long will check for an overflow, but it does allow negative numbers. Huh, okay. So could we somehow showcase this number in a negative form that our program would look at and trick and get us the actual value that we want, get us the hex address for the win function? Yes. And it takes some magic tricks that you may not just kind of know off the top of your head without having been in the scene for a little bit, so I'm going to drop some knowledge bombs here. Please beware. And I'm going to talk about signed and unsigned integers and two's complement and how they're represented in C and C++ and stuff like that, particularly C in this case. I don't want to accidentally say something that I didn't mean to or whatever, so don't hate me in the comments. When we're talking about storing signed and unsigned negative numbers and stuff in C, the way that that happens is by taking the amount of bits that we could possibly store. So it's a 32-bit system in this case. So we have 2 to the power of 32, except we don't have that many. We actually have to keep in mind that we're going 2 to the power of 31, for someone could probably explain that to me, power of 31, and you'll note that this is surprisingly very, very close to the same number that we saw when we ran this guess number code. In fact, just one more because I guess one has to be obviously reserved for zero and stuff. So this is the maximum number that we've got and the way that we actually store a number in C is a particularly form that we take the original value with 2 to the power of N and being the number of bits that we have to work with minus 1, so 31 in this case, 2 to the power of 31 minus the original value of this binary being stored in a 32-bit value. And you can tell that it's kind of be considered that way because there is a one at the very, very front and all these zeros in the end there. So the way that that is stored as a negative number is by taking this 2 to the power of 31, subtracting out all of the rest of the bits, the original bits before the one is on there for the computer to note that, okay, this is a larger value than our regular sine value. So it has a negative component in there. And we're just going to care about this bit here. So if I take this bit before the most significant bit one and the following zeros, what we can do is we can go ahead and subtract that. Oh, forget, got to do that in binary here. And we have this value, which is it as a negative number, the same representation of it, which makes no sense. It is weird, but I'll show you if I run guest on right here. If we run guest on with a negative that number in decimal, we've got it. We've got our shell. Okay, that's cool. So this is a mathematical way of doing two's compliment. So if you haven't seen two's compliment before, I'll show it to you right now. It's a mathematical operation on binary numbers, best known for its role in computing as keeping track of sine number representation. So negative and positive numbers. The way that we can get a negative value being represented in that 32 bit or whoever many bits notion is by using two's compliment. And two's compliment has a trick where you do two things. You take an original value that's in binary. So let's go ahead and take our original value again, shifted to the left four. So this number, take this in binary, flip all the bits. So all the ones become zero and all the zeros become ones. And then add one. And that's a mathematical way of doing again, what we just did with some exponents and subtraction signs. But let's do it that way. If I take out the zero B notation and I've just got, okay, the ones and zeros. We can do some quick transforms to replace flip bits. I use a temporary value here. So my ones and zeros don't get mixed up. Then I replace all the zeros with ones. And then my temporary value, I'll replace them back to zeros. So now we've got this where all the bits are flipped. And we can go ahead and add one to them at one. You can see we have that exact same number that we just saw when we did that mathematical form. However, it's just a little bit easier mentally way to consider it when you don't have to do that as many, I believe, button presses. Flip the bits and add one if you want a positive number that is larger than the highest integer represented in a negative form. So simply giving that as our value here in negative will give us the correct value when it shifted to the right four places. And it's getting that win function hexadecimal address. Weird, interesting thing. Let's go ahead and try that with the actual remote connection. We can echo it into this pipe that there. And let's just get that value with the negative sign piped in. And we have a shell. Let's go ahead and wrap that in cat so we can keep our shell. And now we can cat flag dot text and get the flag just like that. Perfect. Submit that, rock up on the scoreboard, 75 points. Let's say that as just a simple get shell script, nice and easy. Will that work just fine for us? It will. Okay, cool. So I hope that wasn't too hard to follow. I have to admit that's kind of a hard thing to explain in the way that C stores negative numbers and twos complement. There's a lot of weirdness in it. But I hope that to raise the power of n minus one and being the bits subtracting the original value before the zero or the one indicator that it's a negative number. That's one method. And the method I prefer because it's kind of a two step process is taking the original value, flipping the bits in binary, and then adding one to get a positive number greater than the highest integer represented in the negative form. That's the that's twos complement right there. So cool. Thanks for watching, guys. Hope you enjoyed this. Shout out to all the people that support me on Patreon. Thank you guys so much. One dollar a month or more on Patreon will give you a special shout out just like this on every video that I release on YouTube. $5 more will give you early access to everything that released on YouTube before it goes live because I like to record in bulk and then upload as the schedule goes on. If you did like this video, please do like, comment and subscribe. Please join our Discord server link in the description. It's a cool community of CTF players, programmers and hackers. If you want to hang out with me and other cool people, that's the best way to do it. I hope to see you guys on Patreon. That would be phenomenal. Thank you. I love you. And I hope to see you in the next video. Thanks.