 Hey folks, Adam DuPay here, and in this video we're going to be looking at the Poneable.kr challenge mistake. So this hopefully looks like should be an easy one and it's only worth one point. So hopefully I don't get too stuck on this and I actually haven't looked at this at all. So this is a brand new live hacking. So let's read the text. Always got to read the text. It says we all make mistakes. That is definitely true Poneable.kr. We all make mistakes. Let's move on. Don't take this too seriously. No fancy hacking skill is required at all. Great. I don't feel like using fancy hacking skills. It says this task is based on a real event. Interesting. DH shout out to DH monkey and the hint is operator priority. So this is an SSH level. So if we go in we can see we have our mistake binary, which is set UID mistake Pone. We have our flag that's only readable by mistake Pone. Interesting. We have this password. I don't know what that is. Maybe that's something. Maybe it's nothing. Who knows? So I've got everything locally so I can play with it. So here looking at it. Okay, great. So not too too long. But for one point that is interesting. Okay. So here we have our main. We have file descriptor integer, open home mistake password read only. Print an error if we cannot open it. It's telling us to do not brute force. Then sleep for time zero mod 20. Interesting. So sleep for up to 20 seconds depending on the time. I believe sleep takes in a number of seconds. We can verify that really quickly. Sleep for a specified number of seconds. Great. Okay. So sleep for a specified number of seconds then character password buffer password length plus one. So password length. These are pound defines at the top password length is 10. Then reads in the 10 bytes into the buffer. And then it creates a password buffer to input the password reads in 10 bytes into password buffer to then X ors are input. So interesting. We'll have to look at that. I mean, it looks maybe fairly straightforward and then says if string compare password buffer password buffer O2 password underscore length said operator preference. Interesting. Okay. So it's seeing if we can guess the password. Let's briefly check out this X or taking an zero less than like that plus plus si X or with one. Okay, so that should be easy. And then if string compare password password buffer to the password like password length. Okay. Okay. The tricky thing that should that's standing out to me here is this sleep. So and obviously it's telling us not to brute force and it's doing this sleep. I wonder if we can maybe read from this processes file descriptor. Although I don't know if you can actually do that but that would be something to try. Home mistake password read only zero four zero zero. Okay. Now, why don't we So let's go to this machine. Let's SSH to adhere to SSH. This is mistake. They are all mistakes, my friend. Okay. So if we do mistake, then we do cat PSA UX grip mistake. Interesting. Cannot access proc. Okay. So the proc file system is not executable. So we can do proc self. Can we do that? Okay. Good. So we can get so we can't see all the process IDs, but let's see if I stop this. Okay, let's see. So, okay. So this is actually I think pretty easy because it's going to read. So our input, it's getting our input from so how can we make it? I think if we let's see. Oh, but it's X oring our input. So we can't just okay. So my first instinct was well, this should be easy. Let's do mistake and then give it the input self or proc. Self fd. I think it should be three. So zero one, two. The next one should be three. Right. It can't do that. But okay. So fundamentally, we have to know the password because the password is read only home mistake password to number four operator priority. So the other thing I'm thinking of is, well, if this was not a absolute address, so it didn't start with slash, we could actually try to play some games here, but I don't think we can. Let's do this. Let me look up the bash how to I want to know how do I get the process ID. I think I can do this pretty easy. I can do mistake ampersand. And it's telling me it's 3937. What if I cat proc fd three permission denied? Is that because I can't see this? Yeah, okay. I think the problem is because it's running as a set you ID binary that I won't be able to mess with or see any of the file descriptors here. All right. Okay. So go back here. mistake. We all make mistakes. Let's move on. Don't take this too seriously. All right. How could that think Siri for that? Is there something we can play with string and cop? Close the file descriptor turn zero. No overflows. Yeah, I can't open password. I mean, we could put a password file in there. Force. Oh, maybe that sleep is just in there to make it so you can't brute force it. Okay. So read. So anyway, we can get read to somehow return less than I mean read is going to do best effort. Let's see read attempts to read up to count bytes from file descriptor into the buffer starting up off on files that support seeking comments that the current file offset the file says incremented by the number of bytes read the current file offset is at or past the end of file. No bytes are read and read return zero. What if we give could we open a link? No, I don't think that would work. Count is zero. Read me to check the error is described below. Absence of any errors. Read does not check for errors or read with the count of zero returns zero and has no other effects on success. The number of bytes is returned to the final position of answer. This number is not an error. This number smaller than the number of bytes requested. Um, I mean, it's so that's the interesting thing about read. It's always possible if to return less. So it's just checking if it's less than zero. Close it and then scan f password underscore buff two. It's one point. It says no fancy hacking skills. Hint operator priority. Operator priority four zero zero. So what is the permissions on this? Okay, read only mistake. I can execute it. Okay, that makes sense. It's interesting. I may be stuck on this for a bit. This is I guess what happens when you do this live. Alright, that just returns the turn time. I believe that's the current UNIX timestamp. But hey, let's make certain time returns another time a second sense the epoch. Yeah, that's the UNIX timestamp. Mod 20. And then character password buffer in length. Like doesn't use anywhere. Close file descriptor return zero. Character password buff two. I've got to somehow get that password. FD is the return value I see. So you can see that. Let's see is there a read from that. Is there any way that these error clauses could be helpful. But password scan f percent 10 s into password buffer two. So this is definitely passing the address there. Excellent input. It doesn't output anything. So I can't try to think if there's a way maybe if I don't zero. If you do less, let's see, but password buffer two is never output. So we don't even get the output of our own buffer after this XOR this XOR key flips the last bit. So this. So the interesting thing about this XOR is it's going to let's say if we if we put I don't know 120 in it's going to okay, let's create an environment here where we can. Let's see. It's interesting. 64 bit executable. It's just this wrong password. The other thing I was thinking of is that possible to the timing attack would be difficult because there's roughly a random time. I mean you could probably guess it. But one way to do it would be to try to crack it by by by. But that seems way too involved for a one point challenge. But hey maybe these points are all are all bad. So let's see XOR and the input. If I give it null. Wait operator residence. Operator maybe in the C code? Hmm. Yes I know not to brute force it. Okay. Interesting. Maybe let's open this up in Hopper to see look at this binary and see what it's what it looks like. So operator preference could be a mismatch between what we think of as the C code and what actually gets compiled. So let's look up. We are in mistake mistake. Hopefully this won't be a mistake. Okay. So we have our handy dandy main function. That's right. So probably this should compile. I don't think there's been anything crazy. This is the time that's probably been hard coded in read. If it's this from this like this puts this close otherwise called scan f that we want. And then XOR variable 10 with zero x a. Why is it a oh 10 because we're doing 10. All right. Let's look at this XOR. So for 18 to look at the C code in I for I equals zero I less than length I plus plus s. So s is a character pointer bracket I XOR equal XOR key which is one XOR equals one. I mean this looks pretty straightforward. The local variables. I mean here's the XOR with one moving the byte adding far X is greater than equal to that break far four is equal to far four plus. Oh I wonder if operator preference means on the C code. So maybe we can make this fail somehow if open. Huh. Okay. Let's go with that theory and then let's not sure I got this split screen but I'm not like it. Okay. Let's look at main and then let's says a call to open. So the file. So I like making these strings because this is going to be make this much easier to understand. All right. Let's say this hopper file. Okay. So what is actually happening. So it calls open right shifts it one F far 38. Okay. Let's go on here. Open shift right. Yeah. Excellent. Yes. We can already see this length is different. So length of the script or password buffer. How could I control that? I'm not entirely certain yet. See this is a read. Okay. I mean let's look at these blocks how they actually compiled. So shift right one F. Why is there a shift right? Interesting. And move EAX into variable. So actually just to make this a little bit more handy we know this is FD. So the file descriptor compare the file descriptor to zero at the file descriptor is zero then jump if they're equal if it is equal to zero. Okay. So it looks like the error is not here. This is the what we would think of this syntax. Oh it must be this this less than zero check. Interesting. By doing this shift right I have to think about that the semantics there but can't open the password file call format move zero and this should be a jump to the end of the program. Yeah. So this just checks and does the stack check. Okay. So then do not brute force call time then do some stuff here then call sleep and then so variable 30. So now it's the next thing that's going to happen. Oh file descriptor right. We're going to call read. So this must be PW underscore buff. All right. This is the file descriptor. This is the buff RCI. Yeah. So password buff goes into there. See RCX goes to RSI. The number of bytes we're reading is 10. So then we call read. We test EAX set G moves EV and then move EAX into and this should be length pair. I mean that's this check and pair zero if it is then jump over it if it's not equal to zero. Okay. What's the man to read. I wonder if we can make read blocking. I wonder if we know we can't read that file. Let's see. I wonder if there's a race condition where I mean it's a read only file. Again sex. If there's an error this number smaller than the number of bytes requested this may happen for example because fewer bytes are actually available right now. On an error negative ones return error numbers set properly. Okay. So let's see what happens if so move EAX is length ever used again. It looks like length is it is not but it is used in the results of this checks. The length is not really used. Okay. Well let's see. We know from this that the we need to create a file and this should be pretty easy. We can just touch home mistake password. Let's see CH mod mistake touch password. Oh let's 10. All right. One thing that's gonna be super annoying is that sleep. So let's not that out. So it's actually something I really like using hopper for. The idea is we want to just completely basically modify. We want to not region modify region. So not that it's putting in a not that is exactly the size we want. And then file we should be able to produce new executable that has this mistake no sleep. Why does it need that input? It should not work. It should tell me wrong password. Hmm. Did say read error. That is interesting. Is that from scanf? Oh no that's from here from reading from that file. Huh. Okay. So now that we've been able to knock that out. Let's debug it and debug it. Let's say after that read call I want to see what we can do here. Yeah. Here's where I want to go. GDB mistake no sleep. Breakpoint up there. Run it. It should call read. So next instruction. See why does it need a new line? FD. Oh okay. I think I see what's happening here. Super interesting. So this is something so I just was hitting enter and like why is it waiting for enter? And if we look at the registers here we should be able to see. So actually I haven't completely dedicated to memory the I've done much more with x86 32 bit rather than 64 bit. So we can see the file descriptor should be an EDI. And if we print X EDI we'll see that it's zero. So it's actually reading from us. Why is this happening? Okay. I think we got it here. So it's saying okay. So this is exactly the problem. So it's saying the file descriptor is equal to open. So rather than having it needs to have parentheses around this FD. If it was like this the problem is that file descriptor is returning the result of open less than zero which is which is zero. So it's actually not even reading the password file itself. Ah man. And we can actually it's actually hard to verify this on the server because we can't wait oh not that. So if we S trace this we can see that it's writing do not force and it's actually reading from standard input zero. So now the problem is if we tried to run it in S trace here we would see that we can't open the password file because when we run this in S trace S trace runs as our user. So when we use S trace or any of the P trace trying to debug something it runs as the mistake user not as mistake Pone. So we can't read this password file. So we can't actually recreate this. And the time the sleep thing also throws you off a little bit. So this should be super easy than if so it's reading from our input. So if we do mistake it's going to say do not force. So the problem is this file descriptor is getting set to zero. So when it tries to read it's going to read 10 bytes from file descriptor zero. So if I have my ASCII table let's see and I want this to be easy to type in and so let's say one is 31 31 and read will read a line I believe or just bytes. So is it going to look for so if I do let's see hex 31 that should be one. So if I do plus one that would be or sorry X or one. So it's actually not plus. So if I do 31 X or one that's going to be equal to 30 which is a zero. Okay. So I'm putting 10 ones and then 10 zeros and I should be good. Alright. So let's get that Python that see print. See what I say 10 plus 10 man it was as I think it was as easy as they said. There we go. Alright. So what happens. So when it called the first read. So it's reading from file descriptor zero our input. We know it's reading 10 bytes into that buffer. So the 10 bytes it's going to read our 10 ones and then it's going to read from scan F which also reads from standard input another 10 bytes. So here we put in 10 zeros and what does it do. It takes our input which is a bunch of zeros ASCII zeros which are hex 30. It's going to X or them one which sets the last bit which sets them all equal to one which means our password is correct. There we go. Wow. Operator party. So this is actually a great example of why of why you I mean I know it's kind of standard C techniques but why doing assignment inside of this operator is a really terrible idea. So the safe way to do this would be set file descriptor and then compare that result to less than zero. Otherwise here what's happening is this binding is tighter. So checking it with less than zero and then it's setting it equal to file descriptor. So alright that was an awesome one that actually took longer than I thought but hey you know just learn something interesting and new along the way. So hope you enjoyed this and I'll talk to you later.