 Okay, so we have our handy, so what did we learn about J? You guys spent an hour and a half looking at this program. What did you learn about it? That's a percent S. What does that mean? Maybe format string vulnerability. So maybe format string. Okay, so but walking through for the new people, how did you get to this point? So what was the first thing you did? Object number, maybe. Very first thing you did? No, strings. Strings? You run it the first time. Yeah, that's right. Actually, you run it. Yeah. Well, we did those first. Yes. Okay. Cool. So what does this tell me? There's a string in here that has percent S. Yeah. So loading. Oh, yeah. Right? So what does this tell us? That we're loading it live. Yeah, that it's at least using printf, right? We can see up top that here the printf ASCII is in here. And here we see, here's a string which has percent S, which means this is probably using this as part of format string. We also see other interesting things here. We see the word flag, that's always nice. We see .txt, okay, whatever. We see flag judgment system, input flag, unprintable character, wrong flag, correct flag. All, because at this point we have no idea what this is, all they've given us is a binary. So we need to understand it as much as we can. So now, so now we probably run it, right? No, we don't. We have a flag.txt now, so. Okay. Normally we wouldn't see this. So I'd run it and say loading flag.txt failed. Where did this come from? This output. Flag judgment system. This flag specifically. Where did we see this before? Boom, right? Saying loading percent S, right? Format string percent S means substitute that with a string. So it's substituting in the, so basically we can say, hey, loading flag.txt failed. The next thing we should think about doing is why don't we try creating a file called flag.txt, right? Cool. Okay, now we want to run it again. Now we see flag judgment system, input flag. So I'd probably do something that is definitely not the flag. Just hello, tell me it's the wrong flag. I'd probably just try a bunch of a's. It says wrong flag. I'd then probably try the exact same flag. Interestingly, it cut off your input though. Yeah, so it didn't, so this means it didn't actually read all of the a's, right? That's kind of interesting. There's a string like the column inside the assembly. What was that? There's a string like the column. Okay, so we get flag.txt. We see flag judgment system, input flag. But here, where did I get this from? Right? So this, I'm redirecting the input of, or the standard input of this executable j. When it reads in, it's going to read in from this file. So it read in obviously the exact same flag. But where did this come from? I never typed this in. So how does that correspond to up here? It checks if the value introduced in the scene is a value flag. It says, why did I see I am the flag? When I did not type anything, I'll do it again. So where did that come from? From the flag.txt. So it does the same thing if you're here when I say hello? Where is it? Standard. Help. Help? It's quite a flag. I have two hello's. Yeah. It's telling me what I put in. It's telling if it's right or wrong. More information that we know about the program. OK. Let's see. Which way do we want to go on this? What did somebody do next? Let's just go in the right direction. Object dump. Object dump? So wait. So object dump does takes. I can look at it later. Do what? I think I'm going to look at it later. OK. I'm going over it for some people. OK. So this is the entire binary. It's trying to interpret it as x86 instructions. So we don't have the source code to this application. All we have is the binary file. Right? So now what should I do next? Look for some functions. Look for some functions. I try it. Search for what? Load function. Or load flag. That's what it's on. Or main. Yeah. So load flag, that would be a good guess. Yeah. That was an excellent random guess. Main is usually one you'd want to start with. So you can see kind of what it's doing. And I can see calls here to printf. That's interesting. The call to up. I'm not doing this. Call to get end lines. Call to puts. Call to printf. Call to string compare. Call to puts. So if you don't know what any of these mean, you should look up the man page of each of these. Right? And remember, refresh yourself on what exactly it does and what the semantics are because these are very important. If you have a different kind of disassembler like Hopper, which is a very nice MAC disassembler, or there's IDA, is another option, you get basically the same-ish thing, slightly different, but it does have some nice features. Like Hopper can generate some pseudo code looking like this. So we can see here, it's actually interesting, a call to printf of loading percent f failed. This looks like what we got when our flag was not correct. Right? That's interesting. So the main function here, we can kind of see what... But you can see that even with tools like this, it's still not really clear what's going on. Right? But we can even see and hear some things that we want. Right? So we have flag judgment system, new line input flag. Right? That's what we see. We have unprintable character. That's interesting. Wrong flag, correct flag. And you've got to understand, I think one of the skills that you have to learn when you're doing this reverse engineering things is that you don't always know what... You have to be okay with not knowing what the hell is the stack 2047 is arg0 plus 0xfffffc. No idea what this is. It's trying... What this program is doing is it's trying its best to turn the x86 code into C code, and it's often going to fail. So we have to be okay with saying, okay, that's probably garbage, like whatever. I'll come back to it if I need to, but for now I just ignore it. See, you know, some interesting things in here. I don't know. So, yeah. It was good, like... What? What do you want? So you see, like, the else you have correct flag. So the else that corresponds is correct. You have the if, and it's comparing the base pointer plus some address plus something that's on the stack. So we should be looking at those. Yes. So, okay, so there's a couple things, right? We need to know what's our goal? What do we want from this? Do we want the program to tell us correct flag? But maybe we have to get the correct flag. Well, what's our ultimate goal? Like, we're in a competition. Get the flag. Yeah, we need to get the flag, right? That's... Ultimately, if we could, well, if we could bribe the people to tell us exactly what the flag is, then we got the flag. Super cool. We're never going to do that. I don't think we have enough in our budget of wills on here. You're the treasurer. Maybe you're the banker. So, anyways, so we don't, you know... We don't... It's kind of weird, right? You can think of these as red herrings. Correct flag, wrong flag. I don't care as long as I get the flag. Right? Maybe I do... There is some way I can use this behavior to my advantage, right? But ultimately, I want to find the flag. And this is where we get some of the... Do you remember the name of the website? The score, the CTF Western... Judgement. Yeah, so the... Do you have the problem? And the left. You need to sign it, but I don't... Pound Devils. Oh, do we know the password? The first one? Are we okay with sharing it with everyone? The P is capital under Pound Devils. And the password is Pound Devils. And the password is Pound Devils. The lowercase Pound Devils. Wow, gee, guys. Super good security. We went all out on that one. I think I'm going to post this video publicly on YouTube now. I think it's going to be good. Okay, so we have judgment, right? So one thing is, we can see here that they have various genres or categories, right? So we can see a bunch of poems. So, a poem usually means a poemable. So it's going to be something that's vulnerable. So you should think, four measuring or, you know, four measuring, heap overflow, buffer overflow, rops, all those kinds of techniques that we looked at for exploiting binaries. That's usually what it'll be. But the key thing is judgment is different, right? It is a warm-up, which means it should be easier. So that's also something we need to keep in mind, because if we start to find something and then we go, oh, man, I'm going to develop this super cool, crazy exploit and be like, wait a minute. Would they really want me to do this super crazy exploit just to get the flag for the very first level that's supposed to be a warm-up? So that should help us help ourselves in some sense. Okay. Okay, so we're back here. You had some interesting input there. I had some interesting input. So let's think about all the things that we saw, right? And let's think about where they kind of match up in the program, right? So we think of Maine just from the start. So one thing we don't see starting from Maine is the reading in of the flag or anything like that. Right? We don't see that string that was couldn't load flag.txt, right? So that may tell us that something actually happens before we get to Maine. That could be a first hint, right? Because that didn't, what we're looking at here does not match up with the behavior that we saw. So there must be additional code that we haven't seen. Okay. So we call it the init. So there is a function called init. We'll go back there in a second. Okay. So we do have this printf, right? We see flag judgment system, new line input flag. We saw that. Great. Awesome. So let's kind of step through. It's doing something here. Then it's saying get end line passing in. So the other thing that's tricky when you're looking at this, so you know what? Let's look at it here because this will be easier. So we have the printf. We have flag judgment system, new line input flag. So that's interesting. Then we have the get end line. So we can see what it's doing here. So it's actually telling us, so one of the nice things about Hopper is it's telling us that this is argument one of end line. So what is argument one? Well, it's moving ebp minus 4c into eax, then eax onto the stack. So that's the first argument to get end line. The second argument is 40 into var 60c. And then, wait a minute. No, no, we got 40 onto the stack. So the second argument is the constant value 40. So we were talking about, what was I talking about? Where's Karen? Is he here? He left. We were talking about this x86 that we're looking at is copying right to left. So it's the opposite of object dump. But you can always check by looking at the constants. You can't move this stack pointer into a constant. You can only move a constant in one direction. So you know if you find a constant, you're moving 40 to the left. So we see get end line. I would think, so we know what the program did. It output something and then it got input from us. So if we double click on end line, we'll see it's actually a function that they wrote. So they give us a name. It's called get end line. I'm okay with not knowing exactly how it works unless maybe I think I have to look back at it because maybe the vulnerability is in get end line. Totally could be. So what it's passing in here, if you think about it from you, you're the organizer. You're writing a function called get end line. It's taking in two parameters. One of them is what? What's evp minus 4c? What type of variable is this? Local. Local. It's a local variable. Evp, so positive offsets from evp are parameters. Negative offsets are local variables. Constant fixed offsets are going to be global variables. So it's going to be a local variable. So we're passing that in as the first method to get end line. And then the second argument we're passing in 40. So what's probably going to be this? What's at evp minus 4c do we think? Vf by 5. Not too upstairs. So what do we think this get end line is reading in? R input. That's to read it in somewhere, right? So if I was writing this, I would say that this 40 is probably the limit of how many characters we want to read in for this line. And this is the local variable buffer that we're reading it. So I can actually, how do I do it? Eric, remember how to read in? Can I do it in here? Yeah, you can, but I don't remember how. So I would write down or I would make a note that evp minus 4c in main is a buffer. Control R maybe? No. I said maybe. There we go, name, end. And of course. Which it won't let me do because that's just the constant. Oh, there we go. Maybe it's your mac missing all of it. Alright, that's not working. Okay, cool. So we think that our input that we give is in 4c. The other thing we could look for is we check, ooh, does get end line maybe actually correctly limit the size of characters? Like, could we write over this buffer that we're passing in to get end line to read in more characters? So I think that's actually something that I checked. Did anybody else check that? Like, try to send a bunch of characters in and see if you got a segfault? Never happened. The segfault never happened? Yeah, segfault never happened. Okay, yeah, so that probably didn't work. Then we have this jump over the unprintable characters. We can kind of ignore that. It's using puts to output it instead of printf. So then we get to here and then we see what? Printf. So what does this correspond to in our input that we saw? What we typed in. Right, so this is the read end line reading in the input. And this came from what? Printf. Printf. So if we look in here, how many arguments is printf having here? One. One. And what is it? It's 4C. And the buffer. EBP minus 4C into EAX, EAX onto the stack as the argument, the format argument of printf. It's the buffer. It's the buffer. At this point we drop everything because we think we have. So how do I? Wow, it's even nice. It even tells you. Hopper tells you format. Yes, argument. So it tells you not only argument one, but it knows the printf command. So it knows argument one is format. Cool. Okay. You do all this totally in GDP. So how do I verify my idea of what I should, what I think is going to happen? Percent. Yes. Right. Use a percent character. Use a percent character like this? Yeah. And S. Oh my gosh. So what does that mean? It means we broke the computer. Oh yeah, sorry. It broke the internet. It deletes it. So 32. How can I actually verify it without crashing it? That's empty. That's empty. What's this going to do? Print the register. Yes. Not register. Almost. The address. Yeah. The address on the stack. Oh, fancy. So what am I doing here? Probing the stack. Yeah. So I am, so if we look at the man page of printf, it always comes back to the man pages. And I think it's section three. No, two. Oh, printf. So we can see printf, right? And so we can see that this is, if you're rusty on your C, this is actually the dot, dot, dot here is not just like, I'm lazy, I don't want to write all the arguments to printf. Printf, the printf family of functions are, I'm going to mess up the name. Svaradik or whatever you call them. They take a variable number of arguments. There we go. There's a special name for it. So this means that they take one argument as format and they can take any number of arguments. And that makes sense with how we're used to using format shirings, right? Because we use them to print out a bunch of variables, right? The address that's in the variables. And depending on like how we do that, right? We have a bunch of different flags, a bunch of different length modifiers. We can print things out as integers, as unsigned ints, as doubles. And so what we're doing here, and this goes back into, you get to refresh yourself on function frames and how specifically they're laid out on the stack. But the idea is when we use a format string of let's say percent x, this tells, asks me to print it out as hex. But printf doesn't actually know how many parameters were passed to it. The only way it knows how many parameters were passed to it is you, as part of your format string, telling it each percent x. So each percent x, it's looking up the stack and printing out whatever is there. So all these values, c, this, this, these are all on the stack. So we can write a quick Python dash c, print percent x dot times 50, type that through j. So now we can see the output of a decent amount. Well, not, it's not 50, but a good amount. And I can see it's actually not changing. That's interesting. Oh, it's because I don't have ASLR enabled here. So that's cool. Okay. So at this point, some of us, because we remember format strings, and we go, oh, I know there's a way to take a format string and get arbitrary code execution and do all this cool stuff and get my shell code in there and then be able to steal the flag. At that point, you remember. It's a warmup. It's a warmup. So what can we do with the format string? What are we doing right here? Write a memory address. We can write memory addresses, and what are we doing here? Reading memory addresses. Exactly. So we basically have a primitive where we can read a memory address. But what is our ultimate goal? Get the flag. Where is the flag? What do we know about this program? If it thinks that you inputted the correct flag, it'll print the correct flag. We don't actually know that yet because we haven't debugged it, but maybe. If we can input the correct flag, we know the flag anyways, right? But that's a good point. So how does it do that comparison? It opens the flag.txt and it's put in a local buffer. So a local variable somewhere. The contents of the flag must be somewhere in the memory of this program because it's comparing our input to where the program is. So how do we find it? Good luck. Help us. I go back to here. I look at the functions. This gives us back to our knit. I'd say, huh, we never looked at how that flag actually gets loaded, right? But that's a function that says something. So if we look at a knit, I'm going to do this view. I think it's a little bit easier. We have a function called load flag. That seems super promising, but look at this. What are we passing in? So we're passing in random junk. Well, let's look at it here. Load flag. So here load flag. The first method to load flag is passing in evp plus variable 15. So plus into eax, eax onto the stack. So evp plus 15. Why is it plus? Because it may not be a, yeah, it is a negative number. Okay. Okay, cool. So it's actually, sorry. So this is a local variable. So let's look through all the arguments here. Argument three is the constant value 40. Did we see this before? Yes. What was it over there? The limit of the... Yeah, we're thinking of the limit of the number of characters. So it would probably be safe to assume this is what in this context? The length of the flag. Yeah, the limit on how many characters to read in from the flag, right? We always have to specify the limits. We have some 804a0a0 passed in here as the second argument. And then the first argument is evp, the local variable 15. So the first argument is your input, and then the second one is the file. So what do we need to open the flag? Say that again. So what do we need to open the flag? So it's called load flag. You're writing load flag function. So we already said the third argument is probably the number of characters to read in, right? A pointer where the flag is. Yeah, the pointer to a buffer to store the flag. And what else? How do we know what flag to... From the TFC. Yeah, but how do we know? Load flag. It's called... How does it know? So you're writing it, maybe you want it to be slightly more general. So if that was the case, you'd only need two parameters. But we know there's three parameters. So maybe you wrote it slightly more general. So then what other parameter would you pass in the load flag? The address to the... The address to what? That's the pointer. So we already have the pointer to the buffer where we want to store the results of the flag. We have the size of the flag, the back size of that buffer of the flag. What else do we need? The pointer where the flag... The name of the file. The name of the file. Which file do we actually open, right? And we could... Here, let's do this very quickly. One way to do that. So it's always good to have ideas about what these things are. But then to verify them with actual execution. So I have a break point on that place. I would run it. And I would inspect the stack. And I would say, okay, local variable something 40. And I'd say, what's this as a flag.txt? This is a pointer that points to flag.txt. So what do we think this is? The buffer. The buffer. Where it places the contents of flag into. Right, where it places the contents of flag. Which is what we want to steal. So I'd verify that by first saying flag... Also it has a symbol name called flag. So that would also tip us off if we were very good about reading the symbols. Which apparently I'm not because otherwise I would have taken you there first. This is all good. We can assume we don't have that. Then, so I'm right here. I haven't called load flag yet. So I do next instruction. The string I in the flag. So, now we know exactly where the flag is located. We think if we can read 0804A0A0 memory location we can get the flag. So how do we do that? We're in main. We are at this printf. We actually know kind of... We kind of know what the stack looks like. Right, your stack kind of looks like this. Print all the way up there. To that address. To that address. Let's assume because we have no way to... Well, okay, actually check sec installed. I have it in this one I think. You won't have one. Okay, so check sec is a GF thing that tells us what kind of security features it has. It has a canary, it has non-execute support so the stack is non-executable. It does not have PIE support which means it will not be position independent. It does not position independent. If you have the full... No R path, no run path, no partial relocation. Does that still mean the stack though is going to be... Because it has partial relocation. I don't know what that means. So let's assume that the stack is changing. Let's assume the stack is changing. Right, so we need to figure out exactly how many... The delta we needed from 0804A0A0 to where the current stack is. But if the stack is always changing we're not going to know that. So what else can we try? Let's think about where we are. I'm stuck like this. I'm going to debug right here. If you're going to leave, please leave. I'll just keep recording and you can watch it later. You went there, you went up the first print out for the second one. This is the vulnerable print out. This is the second one. So I know I'm right here. This is called the print out. So I actually saw about... So if I compare this to what I saw here. F84 to D58, F7, FFD3, D0. And so I see the F7, FFD3, D0. It looks like... wait, wait. This is the 842, D58. And is this 3F... This obviously gets changed somewhat. So if I run backtrace, I see main. What is backtrace? Backtrace shows you... It basically tries to walk up the tree of the saved instruction pointers to show you who all got executed. But is this thing true? Is main the only thing that ever executed? There was something else, right? Something else executed in it. Right. And we know that init executed which executed load flag, which then called some other init junk from the C library which somehow finally main gets called. So my restrictions are... So can I read any arbitrary piece of memory with the printf? No, only what's on the stack. Right. The address that I... The only addresses I can read from have to be on the stack. Oh, this is interesting. I think you and I made that differently because I'm going in a different direction. I don't know. So, yeah. Okay. So what do we want to be on the stack? Let's say that this, instead of being 0084 2D58, it was instead 0804 A0 A0. Could we get the flag? Yes. Yes. Are we limited in how far we can go up the stack? Yes. How? How are we limited? By the... We're limited by the size of the input that we can give, right? So we can't pop and look up 40. But what other features do we know about format strings? Can we access... We can access the specific 41st offset. So we can use direct parameter access and do %41$X to print out the 41st address hex. So using that, we could possibly access any memory address from our current one anywhere up the stack. And so we know main has been called. We know main is called. It's been executing something. Oh, we did do this differently. Yeah. But we know that what else got called? In that load flag. In it, load flag. And we saw the code for load flag. Right? The code for load flag does what? Let's say... Where is it? The arguments. Right? Oh, sorry. Yes. So load flag got called by init. So this move, this where? So this is our target value, right? Actually, in two places. So it's here. So where is this moving in? Which location of memories is moving this to? Stack. To the stack. So it's moving it somewhere on the stack. And this happened before us. So init got called. It's doing stuff. Coming stuff to the stack. And then load flag gets called. It's coming stuff to the stack. And then main gets called. Right? We don't know exactly the order. But my first instinct when I saw this was... Maybe this address is already on the stack somewhere. Right? Just as a leftover value for when it got copied on the stack here. So the way you can check this... Oh, there. More than once. In the second column. Like somewhere in the middle. No, second. Here? Okay. First, if you count with zero. Oh, you're counting. I see. That's good. That is the second column. It's literally the second column of the album. So we have right here. And also below. And also below. So if we can literally... So we knew that the first one... From up here, we know the first... The second one is 842d58. So 842d58. So this is 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28. I think if we run this... Wait, it already said that it was 28 offset from the stack. Did it? Yeah. Oh, from here you mean? No, from the hover. In which one? Sorry. Right there. ESPA plus 28. Oh, but this is... 28 plus, but you know what sparked it. Oh, weird. I don't know why it's doing that. That's just random. Yeah. That's weird hover. Stuff. Stuff. Yeah. Because we don't know exactly where that stack is. That's hex versus... His count is decimal, so... Yeah, was it 28? Yeah. I don't think it's 28. I need the dollar sign, sir. Was it... What did it say, 27? You said 28. Escaped dollar sign? No. No, because I'm typing it directly into the program. I can do that and I see 8B1290. So I say, hmm, damn it, that wasn't what I wanted. But I can say, where is 8B1290? This, the last one. Where is it? Sorry. The last one. Yeah, so you're one off. Right, the right. Oh, right here? Yeah. So it's 28. Yeah, so you were right, 28. So then how do I... So I printed out the value that's there, but how do I read it? Percent. Or star? Star what? I can't do the star. How do I do the format string to read it? How do you print out a string in format strings like this? Percent S. Take this guy. For them was, so you can tell exactly what the flag is. They prefix it with their competition name, a bracket, and then everything inside the brackets is the flag. So you go submit that. There you go.