 Welcome, everyone, on this beautiful Friday morning, right on the edge of the precipice of your spring break. So now, I was going to pretend to give you a long assignment to ruin your spring break, but I won't do that. So no ruining of spring breaks. Also, someone pointed out to me that I said I was going to discuss the unintentional solution to part four of assignment two. And they also pointed out that you could still turn in assignment two, part two for credit, so we'll table that in discussion until next month, the following Monday. So we will talk about it, don't worry about it, you know. People are still working on it because I think they did it yesterday. I want them to still be able to have time to do that. Cool. Any questions? How are the questions? Two minutes. High level, low level, medium level. Yeah? Motion for the midterm, please. Huh? Motion for the midterm? Motion for the midterm. What for the midterm? Everything we cover up until that point. Everything we talked about until that point is going to be on the midterm. It's like a normal midterm. Cool. All right. Let's do this. Let's see if we can have our time. Okay. So someone refresh our memory. What is, what does talk two stand for? Time to check the time of use. So what is this kind of attack kind of at the core? So what is a talk two attack or vulnerability? Check a condition at a particular incident time and by the time you're actually going to use the result of that condition, something has already changed. Yeah. Exactly. So the adversary basically can do something, can change the state of the system before you make a check and when you use the results of that check. Basically, or you try to access something. Okay. So we saw an example of this where the access system call and the open system call, so access tries to approximate the real user. If the real user can access this file and the open system call actually opens it using the effective user ID of the person, of the process that is calling it. So if you're an adversary, right, in between that time that the access is checked and open this check, right, you can have this file now point to some other file that you, the user can't access, but the process can because it's running as root. The effective user ID is root. So how do we fix these vulnerabilities? Is there a special function that when you try to access the file the pointer already stays at that location so you don't have to re-interverse the directory? Right. So what, so can we code something securely using this access and this open function based on the semantics of what they have right now, not changing the functions at all. Can we actually make this secure? Somehow make the real open key atomic. Make the whole thing elastic? Atomic. Atomic. But from whose perspective? Our perspective? Yeah, from the operating systems perspective, right? But can we enforce that to the outside using these two calls? Use some locking mechanism? What are we going to lock? But what is a lock? Who is being stopped by that lock? File? So maybe we could lock the file and then do all this commutation so that way somebody else can't change the file. I should think that probably would work in this instance. So yeah, in this specific case, right? So this isn't, that's not really a, I mean, could or could not be a general approach to talk to vulnerabilities, right? But specifically here, if we're able to somehow tell the operating system, hey, execute this kind of with the atomic, right? Execute these statements and make sure that I'm the only one who can access this file. Same stuff. It's going to lock, it's going to be an effective lock on it. They're not going to be able to, is that accurate? Because you can just go and access, you can just follow up with another access to check. Right, so yeah, that is, yes, so open will give us a lock on that file. And so then maybe we can check it afterwards, right, to make sure that it still does a point to the same thing. Ooh, although, but access is going to use the string that we pass in as the filing, right? So once open opens that specific file, right, the operating system goes through all of the directories in that path to check the access. So what if one of those directories we change to a symbolic link to point to a different directory? So yeah, now, so we can't just flip them? Actually, that actually goes to the point of the, I think that actually causes the file name locking to not work. Right, so if we, so let's look at an example of this. So if we have, if you need to convert it to a part, say that again, it would be tricky, right? So if we just did something like lock, right? So if we do this, this means that nobody else can change file name, right? So access is, though, checking based on the string, it's checking that whole path. So if it's, you know, slash, I don't know, bar user temp, right? So it's going to lock this file, but then when it checks if it can access it, what if a bar user temp is now a symbolic link that points to, I don't know, the ETC directory? Now we'll check, can I access our user ETC file? Or no, actually it'll just go ETC file, right? No, no, no. I don't feel like this. Right, so try to access that file in there. Check if we can use it. And then we can actually, when it opens it, we can either change this back to open the original file. So we can actually get it to check the access control of a completely different file if we can control anything in this path. Right, because it's specifically doing the resolution at each of these points. So even if we're able to lock the file, we could still, because that file that we locked can be ETC shadow. Right, if we can get maybe a way on that path to change it to point to a different file. How hard is it to actually perform this with Texas? How hard is it? So I could fill a philosophical question, does it matter? Well, you're going to fill a lot of time, because probably the fonts might already pass on that file. At the time that you're trying to probably update it to the latest thing. Yeah, this sounds like a race condition. Yeah. It is, but we talked about on Wednesday, how what are some ways we can improve our chances as the attacker? We have time on our side, so we could just keep on praying. Yeah, one way is we don't really care. We're the attacker, right? We really need this to succeed once. So we can just keep trying over and over again. And this type of thing is probably going to be very quick. So you can try adding some number a million times a minute. You're going to try a lot of tries. So even if the percentage is very low, trying a lot means eventually you're going to get it. What are some other techniques we can do? What's that time we're trying to enlarge here? The time between the race is the first time and the second time. Yes, the time between the access and the open, right? We want to make that time larger. So what are some other techniques we can use to do that? What if we use physical path instead of D5 name? Use physical path instead of the file name? To increase the time there? We'll talk about that in a second, because I want to... It still could be access and open only access things at the virtual file system level, right? So how do we delay that time between the access and the open check? Increase other processes or something so that everybody's locked down. Exactly. So we can just make a ton of different processes, right? That way everything is slowed. And so now we increase our probability of hitting this. So in general, that's why kind of the question is, well, how likely is this? Well, maybe a demo attacker, it's unlikely, but attackers are smart and they only get better and smarter. Wouldn't another way to mitigate against this is to lock against all of the directories along the pathway and the file? Lock along all the directories, but how can you be sure that every directory in the path... That the state of the directory as in it's not a symbolic or it is, that state doesn't change and it doesn't point to anything else. What if it is not in the path? Like if it's not in the path of human and the symbolic one is in a different path to human? The status attempt doesn't change. It has a directory with files in it so that status doesn't change. Whereas here we change the status from attempt to being as involved into some other direction. On the top of my head, I don't know. I think I have to get the play of it and check it out. That could work, but then we have to do a ton of extra work, right? And we have to make sure that we do this correctly every single time we want to check access and open a file. Ah, it unjinxed myself. Okay, so one thing that we can use. So what is the problem with using the file name? It's a string that the operating system has to parse and go through and access every file, right? When we call open, what is the open method returned to us? A file descriptor, right? Because our process has opened that file. And so what if now we use, let's say, versions of access that operate on a file descriptor? Right, is that going to solve our problem? See some guesses and some no's. So if we go back to the code here, if we change this to first open it, right? And then check using the file descriptor that open returns and not the file name. A different version of access that uses just the file descriptor. So what is this file descriptor that open returns? That's just the number that the operating system uses to map a file that our process has opened. So it knows, it'll actually be incrementing, I think, out of. So zero is standard in, one is standard out, and two is standard error. And so I think when you first open a file it should be file descriptor three, and then just incrementing from there. So the OS keeps track of, okay, file descriptor number three, maps to open file, whatever that example we have was bar test status file. And then every time we say, hey, can I access this file descriptor? Right, the operating system has already opened that file for our process. It's just like when you have an open file open, right, and you're writing to that file, to the file descriptor, there's no way anybody else can force you to write to a different file now. Right, because you have, that's kind of like, that file descriptor is your pointer to that actual file on the disk. So then you can ask questions like, can I access this file descriptor? Right, the file that's pointed to by this file descriptor. And it doesn't use the path, it doesn't use anything, because we've already done that parsed and returned a descriptor to the file. So that's one way, is use system calls that only refer to file descriptors and not path names. Right, that's the main problem is the operating system re-looks at the path, and so these objects that we're comparing, hey, can I access this thing versus open this thing? Right, they're different objects, somebody else could make them be different objects. But if we say first, hey, open this thing and the operating system says, great, this file is file number three. And I say, great, can I access file number three? And then you can check, right, because it knows that exact file that's been opened. So re-parse everything. To do this correctly, you need to first bind that file descriptor first, before you actually check anything on it. So the first thing you should do is you try to open that file, and then perform things on it. And so, and then we looked at a little bit before. So the same advice about using temporary files also applies. So you want to use the make secure temp file if you want to create a temporary file, because this will ensure that, A, that that file does not exist, and make secure temp will return a file descriptor. So it will return, create the file, return you a file descriptor that you can then write to. So it doesn't atomic create and write, yeah. I'm not sure, could you, if you don't have it for a pan, you have it for you write a new file, and you still trick it into blanking out a file. So if you have it, I don't know the term, but if you have it for not a pan, if you open it for, you know, not to a pan, but actually to, you know, where it resets the file, recreates the file. Yes. Can you blank out a file then still, could you? I think so, yes. So be careful, careful too with your file permissions, right, because often you can open it, I think, with a truncate flag to be able to open a file and automatically truncate it. So open uses the effective ID, right, and access uses the real ID. So, yeah, you can be opening any file and potentially truncating it, which could have really bad security consequences. Absolutely. Any questions? Go check, I'll use. This is actually really fun to do. Okay, so it's thing, and like make it run, and then all of a sudden it just works. It's really cool. Yeah, just a second. Does all this apply to programming and Java, because it has its own JVM and all of this just, does it follow the same, like, where is it? I hope that you find it real, I think. You have to dig into the exact semantics, but yes, if you check a file's permissions based on a string, right, and then you open that file based on a string, then absolutely, right, at the end of the day, Java, the JVM still has to call out to these C functions, right, which is kind of why we're studying it at this level. But that makes it a little bit more harder for you than reason about, can this actually happen or not happen, right, because it depends on the semantics of Java. But you definitely have to keep this in mind, that yes, there's a possibility. You have to know, hey, could somebody do something in between this check and this access? Okay, there is a symbolic link to the string file, so if you are using file as the code that would be used to go for language. If it's a link to the same file, if you train it, you need a link, a symbolic link that points to itself. So I like it different. But that points to a different file. So when you call open and you get a file descriptor, it resolves all symbolic links. So the file that you get is, that points to the actual iNode on the disk, right, like that's the thing you're reading and writing to. Cool. All right, so more file based attacks that we've been going over. Another really cool one is called the file handler reuse, and this actually goes into and goes back to the file descriptors that we just talked about. So the idea here is, and remember, we care about setUID applications, right, because they have more privileges. Oftentimes, these applications have to open files, right, which makes sense. They're special root applications. They have to open files to perform their configuration or do whatever they want to do. So for instance, Apache, like a web server. So is Apache your web server's setID root? Yeah, oftentimes they are. Why? Access to several things to switch on. There's a very specific reason. 40. So good. What was it? 40. Yeah, port 80. It needs to be able to listen on port 80. All ports below 1024 are considered privileged ports, and only root can bind to those addresses and listen on those ports. So specifically, Apache does this, attaches to port, listens on port 80, and then immediately gives up all its permissions and usually shifts depending on your OS, I think. What it'll move to is www.datauser and other systems are maybe like nobody or something like that. But there's usually a specific user, so that way if Apache is compromised, only that user, it's not root that's being compromised on your system. But applications like Apache and other setID applications will sometimes fork external processes. So why would you fork an external process in general? So what is forking? Eating food with a fork. Very similar to forking, but with longer times. Using someone's code and building upon that, that's maybe why you want to execute an external process. Specifically, what does a fork do? It creates a new process. It creates a new process, and what kind of new process specifically with a fork? A child process. What's the code of that process? Yes, same as the forking process, exactly. So it's basically... Oh man, I'm going to try and remember probably your knowledge of biology, hopefully it's a little different than mine. It's like cell, is it mitosis? Yes, that's right. We're like one cell splits into two cells. That's exactly what happens with processes. When you call fork, the operating system goes okay, great. I'm going to copy all of your data. I'm going to create a new process. I'm going to copy all of your coded data into there. And you're going to start executing from exactly the same place, which is right after this fork call. And the return value of fork is different depending on if you're the child of a parent. So by testing that, you can tell, hey, was I the forked? Am I the person who called the fork? Or am I the parent or the child of this cell process division? So actually this is... Let me talk about it. Actually a classic security denial of service attack is a fork bomb. Or you just have a program that says, well true fork. So the first time, right, it's going to split into two processes. And then each of these are going to go and they're going to split into four processes. And then each of those is going to go and split into eight processes. Or no, right? Yeah. And then it just goes exponentially, right? Which is kind of awesome. And you can actually, if you do this on an Android phone, you can break it completely. It's crazy. This super old thing still works. It's actually really fun. When we were looking at Android vulnerabilities, there's a way on certain versions of Android where you could get them to execute arbitrary code just by visiting a website in their browser. So if you visit your browser, we download this fork bomb and then execute it from JavaScript. And so you just have all these processes. So you go to this website, your phone would, in a sense, be ripped. Like, hard reset it. Anyways, it's really funny because also Google does not think that that fork bomb attack is a vulnerability. Okay, so back to our thing. Okay, so what things are copied over when we fork a new process? So the code, the data. I actually think I have to look at it. I don't think the setUID bit, I don't think the effective user ID is kept. I think the child is going to be executed with less permissions. Which makes, I think, make sense. But I'll have to check that. But maybe permissions, probably not. I think for this specific attack, we'll assume that it drops permissions. But what happens to the files, those file descriptors that the parent had open? Yeah, they're also still open for the child. And this is actually how parent and children processes can communicate with each other. So what actually happens, like when you call system, to execute this process and return the output, what actually happens is the parent forks the process, sets the standard out to be some file descriptor of the parent process so that anything that the child writes out is going to be written out into a file descriptor that the parent can read from. So the child thinks it's writing out the standard out, but really it's going to the parent. So with all these kind of tricks, they also inherit all open file descriptors. And specifically, okay, so we have four game creates a process, but then that just clones the current code, right? And that new code can detect if it's a child or a parent. But then how do we execute a new process? If statement on which one you are and then just... What's called specifically do we use to execute a new process? Exec, yeah. So typically, if we want to execute a new process, we fork our process, and then we check if we're the child, we immediately call an exec to execute whatever program. So the exec system call, let's look at it. I think it's man five, exec, oh, three, I think it's three. So this would be system, and this is the VSD version, but that's fine, I think for here we're going to make 200 difference. So there's actually a significant... There's a lot of different exec functions depending on how you pass the arguments. So... Did my mic go off? No, is it working? No, okay. Well, it's happening in my other class too. Okay, so the one we want to look at... Let's go to the Linux machine, because... All right, we're going to go to the Linux machine because it's a little bit different than what I was expecting. So let me get a new matter. Oh, it handily says dead battery and exclamation point to let you know that it's a very serious issue. Spring break. Okay, so the function we want to look at is the exact VP vector. Yeah, okay. So all of these functions, right, understand what these functions do. We read the very first line of the description. So the exec family of functions replaces the current process image with a new process image, right? So that means we can completely wipe away our processes memory, code, everything with this brand new process. And so... Ah, that's what I want. Exec Vee, that's the one I want. Okay, so this is the actual system call in the operating system. So all of those other calls are helper functions that translate, that eventually call exec Vee in the kernel. So this is what the kernel gets is this call. So it says it executes the program pointed to by file name. So file name must be either a binary executable or a script starting with a line of the form shebang, right? So if you've ever wondered why you have to do a shebang to execute a file, it's explicitly because of this system call, this exact Vee system call in the Linux kernel. And it's telling you exactly. It's got to be a binary, right? And it's got to be an executable, right? So this is why if you have a Python file that doesn't have the shebang here, if you try to just execute that Python file, it won't do it. But you can call Python that file where Python is an actual binary executable file that that file knows how to interpret your Python file. Okay. So it's going to look up file name to try to execute that specific file name. So this could be slash bin slash ls. It could be slash user slash bin slash Python. Whatever it is that has to be either a binary executable or a script that starts like this. So argv is going to be the vector argument. So what's this mean that it's a vector argument? We know the number of arguments. So actually, okay, let's look at this. So let's read it. Argv is an array of argument strings passed to the new program. So this is explicitly how your argv parameters get passed in a single program on legs get passed in this way. Environment pointer, remember we saw the environment pointer on our stack, right? So we saw at the very top of the stack is the actual arguments and the environment data. So the environment pointer is an array of strings and each of them are of the form key equals to some value. So these are then passed as the environment of the new program. So when that program looks for its environment, it's in there. So both argv and environment pointer must be terminated by an old pointer. So specifically what the v means in there is argv is, so if we try to take this apart, right? It's a character pointer to an array. It's an array of character pointers, right? Another way to write this would be it's a character pointer pointer, right? And each of those elements of that array is going to be a pointer to some character array, right? And then if one of those pointers is null, that's how we know we've reached the end of that argv vector. So what does your program get when your program executes the main function? argc and argv. So then how does, but are we passing argc in here? No, exactly. So this means the Linux kernel actually counts exactly how many arguments you have and passes that as argc to your program. And that's how that gets to your program. Okay, so do we look at what's argv0? Yeah, it's usually the name, by convention it's the name of the program that's actually being executed. So actually, but you don't actually have to pass that in. You can actually pass in with argc as 0 by just calling execve with a file name and null for argv and whatever you want null for environment pointer. I'm going to get into this radical. So this is actually how I don't know, a backup term. Okay, so all this is how every process gets executed on your system. So when you're at the bash terminal and you're typing in ls eventually what happens is bash forks a new copy of the bash process and then it calls exec with slash bin slash ls as the arguments and then you're passed in. And then when that program executes the Linux kernel then goes loads up that ls file, loads it into memory parses that l file and everything and then starts executing your program. These are exactly the steps that happen. So if you're a set UID application and you're trying to fork and execute some external process right? So your code is replaced, your data is replaced but unless you if you don't specify a specific flag then the new process is going to inherit all of the original processes open file descriptors. So why might this be a problem? So what can this new process then do? So let's assume that when we fork and exec our child process that exec is going to drop the set UID privileges. I have to look into it. I'm not 100% sure that that works but I'm 99% sure. So we can't just arbitrary the code that's going to execute is not just going to be able to run arbitrarily as root. Right? What can we do with these file descriptors? Exactly. Now, those files are already open right? So if we trick the set UID application to open a specific file right? And then we get it to fork and exec while that file descriptor is still open right? Before it's called close execute some code we can control now we can read or write to that file whatever that file descriptor was opened as. So this may be kind of bad. I mean that's not a technical term but this could be bad if you know if it's a configuration file or maybe some file that we shouldn't be able to read and we can only read to it or maybe write to it but if it's a file that if we can control that file that's opened then we can influence the application to open any file with their permissions like EDC password or EDC shadow and then read and write to it after the fork and exec. Right? So this is kind of a big problem here is if those open file descriptors have some security sense of information and so this is a classic vulnerability so this vulnerability happened in the C8 pass program so this was back on OpenBSD systems and it allowed so change pass so what does it change password? Change pass things very simple a way for you to change your password right? So should anybody create a user on the system be able to run this command? Yeah. Does this command probably have administrative powers? Right? And it's got change of password right? So you don't want any user to be able to change the password but you want all the users to be able to execute the program and so this is most likely a set UID program running his group. So what CH Pass would do is it would create first a temporary copy of the password database then it would well you're writing CH Pass. What would you do? How would you make it work? It would be nice. You're going to make a copy of it right? So that way you don't have to raise conditions about multiple things writing to it. So you make a copy but how are you going to let the user change their password? You have to let them enter their old password but then they want to enter their new password. So you can have a password prompt on the command line. That's super lame. Right? I use Emacs. What if I wanted to edit my password with Emacs? Or what if I wanted to edit other passwords in the password? I mean none other passwords but this was like a database, password database right? Maybe I want to edit other information associated with my account but you're a friendly CH Pass developer. You want to empower your users to use whatever editor they want. They want to use Nano or VI to edit their password whatever. Like when you write a Git commit message right? And you don't specify or when you commit on Git usually if you don't specify some specific message on the command line it will pop up an editor for you. Right? And that's actually based on your environment parameter of editor. So you can change that editor thing to change which program is executed right? So it's actually Git is using your environment variables to decide which editor. Okay. So this is what it do. Okay, great. Here's you know, here's an editor now you can display and modify user information right? And I like this because this is something that any of us could do right? You think I'm going to do this feature right? They want to edit their passwords? Well bang! Instead of just lame-o typing it in like you have full editor capabilities right? Do whatever you want. So then after they saved it right? They copied that information into that temporary password file and then that's used to like rebuild the password database. So what's the problem here? I get to see the information even here. I I I probably could put in some relations thing so that when it's copying back it could for a coprocess or something. I mean I could put something in the editor which Let's say it's very secure. I mean in that sense it's copying the files correctly. Right? So what are you saying? Okay. When you spawn editor it shows you like some information right? We spawn the editor in one sense. Well, so it's spawning it and displaying only your files. How is it executing this editor? Environment variables? Yeah, it's probably using this path to determine the editor. It's forking a new process for the editor. Forking a new process right? And then exacting the editor. You call system just like you did for your backdoor program right? That's exactly what system does. It forks and execs a new process. Right? So what file descriptors are open? The temporary file. The temporary file that has the database and everyone's password. And you're running VI or you're running some editor. And so on some editors you can use an escape to shell. You can use some kind of shell feature to execute arbitrary code. You can also just change your editor or change VI to be whatever binary you actually want. That's not actually an editor. And so this shell that you spawned from, so here you're forking another, you're copying and forking this escape to shell. It's going to fork an exact new process which will be bash or sh or whatever. And now that process also has this open file descriptor. And so you can read that entire password database. And any changes you make, changes reads or writes to that temporary database are going to be merged and changed back into the original password database. So from here we were able to it seems legitimate in some sense. It seems like this is a feature that you would want and you'd brag about. It's a cool feature to edit your information. But because the file descriptors were open when forking and exacting children processes and the parent process had that specific file open and hadn't closed that temporary file or done anything with that temporary file. This is the problem. So how do you fix this? Copy back only that user's information back into it. Copy only that user's information back in there? Maybe. It's not like a I'm not going to work in every single scenario though. Like in general not just this attack, but how to fix this class of attacks. You have to set that flag. You have to set that flag. Or close it yourself. So you need to ensure before you fork and exact a process that there's no way that those programs can inherit your file descriptors. And also that or you have to make sure you close any open sensitive files before you fork a new process. Kind of an unintended side effect. One of those weird features that's pretty technical but super interesting. So the next one now we start getting into some media stuff which is awesome. Command injections. So command injections really are a huge so here we're talking specifically about OS command injections as we'll see but really command injections is an entire class of vulnerabilities that spans here in local programs with the channels we'll see but also SQL injection is an instance of command injection and cross-excripting is actually an instance of command injection. So these are all instances of one kind of class of vulnerabilities. So that's why it's really cool to talk about. So as we saw with the previous example why didn't we want to do that fork and exact? Should we just tell developers that's stupid you shouldn't be doing that? Why are they doing that? To what? To run something else. Is that a good software design principle? Yeah. You're essentially reusing somebody else's code or program. It's like hey I shouldn't have to develop all this stuff myself. I don't want to develop like the change pass shouldn't include an entire text editor just to give you cool text editing features. It wants to be able to execute some external program to do that. And so applications want to do this and it's reasonable that they want to do that. This is kind of one of those things when you're thinking about security issues. You know the easiest fix is to say well never do that in your code. Don't execute external processes. Well okay we actually have to understand why are the developers using this and if it's for legitimate purposes then nobody's going to follow your security advice and never to do that. They're just going to be like you clearly disconnected from the actual developers. You're spewing this security advice and you don't really know what you're talking about. So we know that they do that. So for instance this is why you got familiar with the system call in assignment one in the backdoor program. So what are the semantics of the system call? What exactly does it do? Because I know some of you chose to do assignment one in the backdoor in Java. So does Java have a system call? Like C? No. I see some of you shaking your head. No. So what did you have to do? We created a process from the entire life. How did you know to do that? What are the semantics of this system command? What does it do? Calls a kernel module? It does. But what are the semantics of that? It's a system call. It's a sys call, right? So it goes into the kernel. What does it actually do? What are the exact semantics of the execution? How can we find out? Looking at the documentation in the mandate. Yes. Yes. Okay. One, two, three. Okay. System. Execute a shell command. Include standard lib.h. Actually, maybe it's not in the kernel then. Maybe a libc function. I think it's going to eventually call exactly e. Which is the other command we saw. So we see that it's a call, and it returns. It takes in a string parameter. So sometimes the question we want is right there in that very first sentence. System. Execute to command specified in command by calling slashbin slashsh dash c command. So what are the semantics here? Exactly that. We know that it's identical to calling slashbin slashsh with the dash c argument and then giving it a command. And we can see here it's actually going to do the fork for us. It's going to do the fork in exact for us. But now we have to know how does SH work. Because that's it's calling, it's basically saying I'm calling another program to do this. So luckily we can kind of scan this and see awesome dash c string. This is exactly the option that's being passed to SH from our my program. And the reason why when I did mansh it brought up the manpaid for bash is that if you look at my system you'll see that binsh is a symbolic link to bash. So there actually is no SH program on my system. It's actually bash that's getting executed. Okay. So it says if the dash c option is present and the commands are read from string if there are arguments after the string they're assigned to the positional parameters starting with $0. So this does So what is doing? Is it running the command of a string? Is it running the command ls-la- slash for SH to parse that string then execute that. So what does SH do? How does it know which command to run? The first question I'm running in bash right now. What happens when I hit enter? When c is already listed since you're under the batch Exactly. So one important thing to get you to map this to what you already know binsh dash c. This is exactly as if you wrote this on the SH command line. Important thing actually, you'll see there is a difference here in the color because the environment of SH doesn't have the color thing set on the terminal. I believe if I did it to B and B we could probably figure that out but we can kind of go down the radical. Okay. But how does it know to pass in L? So at the end of the day, it's going to execute exec ve and this file name has to be an absolute path to that file that's being executed. So how does it know which file to execute? So did I specify the exact pass to LS? So how does it know which LS what to execute? From the path environment variable. Yes. Bash what's up in the path. Okay. Is there an LS in the first part of the path? No. What's in the second part of the path? No. Is there an LS in the third part of the path? No. And so on. If it finds it then it knows that that's the program. How does it know to pass so what are these parameters passed into the LS program? It's going to be the arguments, right? So what's the LS program? What's RV0 going to be? The string LS exactly. What's RV1 going to be? Minus LA and RV 2. Slash. But how does bash get that from here? How does it get from here to here? Because this needs an array of pointers to LS dash LA and then slash. Are there any spaces in here? These arguments? So how does SH do that? Each of the items is part of the newly created rank to be passed. So SH or bash itself is parsing the string that gets passed in as the slash C parameter and it's splitting that string based on the white space and then it's parsing that first token of that string that gets passed in. Look that up in the path to try to find the file that's executed. And then take that second thing as the argument but it's not just white space, right? What if I did something like oops, what if I did this but I have this dash in here? What's that going to do? It's going to escape the space. What does that mean? Escape? Ah, the space is escaped. So the first argument would be an LS space. Yes, it parses it as if the first argument. So what's it going to try to find a command name? LS space slash LA So it's going to tell me that that command SH is saying I could not find that command. And so this is exactly the same thing that happens if you try to type this into your terminal here and your terminal is just batch which is exactly the same thing that the system does. Do this, it's going to tell you it can't be found. And so this is why right, why are these things different? Yeah, so it's splitting it right, it's tokenizing it based on the spaces. But what does this mean? What is this telling to batch or to SH? What was that? Yes, that that consider this as one thing so when you split it up so what's in this command, what's RGB 0? LS and RGB 1? Slash bar space ETC Exactly, so if you're ever struggling with passing spaces and the programs and that kind of stuff this is how you do it and this is why and it all comes back down to this mandate but this is how it comes back down it comes back to this argument the operating system only knows how to execute programs in this form so any program that wants to execute a program has to translate it into this and so you the programmer have to specify or there's a library a whole set of libraries like system and the batch command which do this which take your input and get it ready to be passed here to be executed Alright then we'll see how we can subvert this process for our own nefarious means when we come back into this