Playing wargames with Rust
Hello. My people today we are going to be using Rust to play a war game. So a war game is kind of an old way of saying what we would now call a CTF or capture the flag. It's basically a series of technical challenges that usually involve basically hacking like trying to do something hacky to get in and uh exploit stuff. And this one we're gonna be doing over the wire. Over the wire is one of the most popular well known war games out there, especially bandit for learning basic Linux. But my first over the wire war game was Vortex and you get started, you have level zero basically just use programming to do cool security stuff. You also do exploitation, all kinds of stuff. But the first level is very program oriented and I want to show you how we can use rust to beat it. That's right. So sorry, I mean I'm in this rural area of Guatemala, There's tons of plants outside, which is beautiful, but it gives me crazy allergies. So I'm always like sniffling like crazy on these these code casts. There you go again. Anyway. So your goal is to connect two ports 5842 on vortex dot labs out over the wire dot org and read in four unsigned integers in host byte order, add these interviews together and send them back, send back the results to get a user name and password for vortex one that's the next level. Right? So each time we're gonna get a password that will allow us to use this information to use can be used to log into ssh. So I have to log into Ssh and then I'll be able to do the next level. Note vortexes on a 32 bit X 86 machine meaning a little indian architecture. I see here we have helpful reading material C programming and network programming. This network programming guide is one of the best pieces of technical writing in the universe. Its beaches guide to network programming. It is the guide to network programming. It uses C. So if you want to learn about UNIX programming, this is the way to do it. But it does use C. So he also has a guide to see. That's really good too. Alright. Anyway, so Let's get started. So we have to connect support 5842. So let's start by doing that. Oh, you know, I have this dependence in here that we actually are gonna need. So I have a little rushed project for us. Sorry, excuse me man, how to blow my nose. This is nuts. Like I've never had this many allergies in my life, but I've never been in a place so beautiful. So I guess it all evens out. Okay, so the way we're gonna connect so we'll create a stream that's like our by our socket. You might call it if you're used to, you've read beaches guide. That's how you'll know it. So we're gonna have to connect on the porch they told us about. So I'll say I'll use TCP stream and connect this will give me a stream. I can read from. I think if connect with a capital C. I have some notes about network programming lowercase. I don't do this often in rust. Like how often are you using raw sockets anywhere? Not just in rust, but yeah, these aren't raw sockets. Right? This is gonna give me a little stream that I can read and write from, which is great. But it definitely makes me think of python. I like python, you know where you have your little socket like as equal socket dot socket and you just say received and it's so easy in python. But rust actually makes it really easy. Like especially compared to see, it's almost like python right now we're doing some some lower level stuff. But I mean I'm pretty sure Russ could do this as easily literally as python, which just like read, write. I don't care. And by the way this returns an option. So ST I mean a result, right? So it could be an error, right? It might not actually connect. I don't want to do a bunch of nested error checking. So I'm just gonna say, hey, if it doesn't work, you can use this question mark operator say, hey, if it doesn't work, just return an error from Maine right now And in order to do that, we'll have to say, hey main is not going to return a result That will either be this little void empty thing or it will have some kind of error. We could put the specific error here. We're actually gonna do this multiple times. So it could be any type of error. So I'm gonna put it in a box because why? Because it could be different sizes. Different errors. Take up different sizes. It's not gonna know how to allocate that. So we'll just say, hey yeah, this is gonna be an error. You do that? I'll have to include error because it's not in the default name space. Okay, so that should work. And then we'll just print something to see if we got here. If we got here. We'll say, I don't know connected to wait a sec. Why am I not getting why am I not getting my strings highlighted? Maybe I don't have a I need an extension or something. I'm gonna check rest installed. Okay. I just noticed that I don't have code, like I don't have syntax highlighting really. Right. Like I have some kind of syntax highlighting, like my strings aren't even highlighted so that's no good. It says it's there. Uh Yes, yes, install. Okay says it's successfully installed. I'm gonna go back to my terminal and let's try running it. Let's see if we can connect. No, we cannot. Why? Because I'm closing this box but I'm not closing this result. And so what's I am now. Okay, there we go. And this rusting I'm using is pretty upset because I need to say let oh I have syntax highlighting. Oh my gosh guys I have syntax highlighting so it's mad because it's saying hey you say that this is returning this but you're never returning like I have this option where if it fails I return but what if it works? Well that's why I need to have okay now it'll be happy about that. This is like the success version. Oh I didn't make it happy still let's see why. Mhm. Just check something out and right right so it should be returning it from this because it's saying hey yeah you're just doing okay on this but you're never returning this failed in um where there's an option where it could be a failed result. And that's because I'm trying to import TCP stream, I'm trying to use it but I never import it. Let me go to my notes because I forget I forget how to import it right from standard library net. There we go. Okay that should make that air go away. But it doesn't let's see why the reason is let's see oh right because I have a semicolon here making this a statement. It needs to return that. Here we go and now it's happy but still mad about TCP stream. Um Right let's see what I'm giving it an error. Oh wait wait it only takes one argument. It's actually a string like this like a U. R. L. Schema type thing. And now it's just mad that we're not using that argument will work but it gives us the warning but I'm not gonna underscore it because we're about to use that right now. So so we've connected. So I'll go ahead and stay connected to O. T. W. For over the wire. And now we need to read in some bytes. Right? So let's just try reading in one bite and seeing what happens. Okay? So we need a place to read the bites too. So I'll say let fights big work. We'll have an array. Uh it'll be it'll be the # zero. Right, as an eight bit unsigned integer in other words, as a byte and we will have four of them. Why do we have four of them? You might be asking because it says we're gonna read enough. We're four unsigned integers. Um presumably this is coming from the eunuchs and see tradition, in which integers are just four bytes. Unsigned ints or four bytes. They don't have to be, I don't think that's actually part of the C standard and I mean they even never mentioned. See up here really. So why is an integer? You know gonna be that big but no biggie shh we'll just make the assumption and host byte order. Okay, that means it's gonna be big indian, yep. This is going to be I think or is it little indian that I always get my indian mixed up, I'll just read a post by order. Yeah, that's a little indian. But all that means is when you're writing binary, uh you know, you have the smaller numbers on the right usually and the bigger numbers on the left, that would be That would mean that that's big Indian, right? You start with the big numbers like think of the report number 5001. Why isn't this 100? This is the 10th place, right? This could be the 100 plates, the templates in the ones place. How do we decide that? The big numbers go on the left, when the big numbers go on the left, that's called big Andy um in the case of the decimal system, it's just a tradition you can do either or right. So uh we all had to agree though, like when you're sending binary over over the wire, which is it gonna be? Hey, I said over the wire, no pun intended anyway, they all had to agree because different architectures used to do this differently, I think nowadays they've all kind of agreed on one or the other, I don't know which, but it used to be that that architectures were all over the place. So in any case on the network though, everyone had to agree to do the same thing so that they could read each other's binary data that's called host by order which apparently is a little indian. So that means that this number would be 105. This is This is five, this is the 10th place and this is the hundreds place. Alright. So the reason that matters is that when we're converting bites into an integer we'll have to say well are these bites? Little indian or big indian? Alright, beautiful. So let's get back to our code. We set up these bites and now we can use the stream to say we want to read and we actually want to read exactly. So many bites. Alright. So we can say read exact and then we will say read it into our bytes array. All right. And at least I think that's I think that's how you do it. Maybe it's not read exactly, look it up. Rest TCP stream read exact. Okay. All right. So it'll fill a buffer. It looks pretty legit to me. Oh right, right, right. So this is gonna be on any buffer. Okay, so this will return a stream. Yes. Yeah, that should still work. I don't know what am I doing wrong. Mm hmm This works on any buffer. Let's see. Let me just look up rust. TCP stream. Example if I can find something good. Okay, so let's try read. Yeah, this has read exact. So yeah, it says stream. Right. Let's see. Stream is matched from TCP connect, you know, maybe maybe your editor doesn't know what he's talking about. Let's see what happens Ha ha we don't have the read method. So we have this I. O. Read. And in order for that trait to exist because it's saying it's not found right? Not found. We need to import it so I'll import it from here cause we're also gonna run right later. So I just have these little notes ready. That should do the trick mismatched types and wants to take ownership. I guess no one wants to be beautiful. Weird. That doesn't make any sense. Not borrow. It is beautiful. Well let's change that. Make it mutable. I borrowed is mutable because it's not here we go. And we don't do anything with the return type so this could fail. So we'll need another little question mark. Mhm. And we should be able to do it and it says we connect I can get rid of Hello world. Okay We can act. But how do we know these bikes work? Well for one one of the first things we're gonna wanna do is convert these bites into an integer. Okay. I believe we can use the from we have this from the feature that we should be able to use. I think it looks like Something Like You. 32. It's an unsigned. 32 from. Yeah I guess that's wow that's actually how you do it. Who would have thought? Okay Anyway I'll pack and then we passed the I will say let and we have to we have to put that somewhere. Right? So let's say wet integer. We're gonna read an integer. Well that it's pretty mad mad at me. So let's see. So it wants to convert it from four bites. Looking legit to me. It's not implemented for you. 32. Uh hmm. What could I be doing wrong? Let me look it up. You say rust can avert they rest U- 32 from Byte Stream. What from bikes already? All right says we can use bike crates. I think we should just be able to save from though. Sorry. I see all these really cool fancy ways of doing it. But I guess we would have to say let me see if I have it on my notes. I do not but it is in fact going to be because because it's binary, we have to specify specifically whether it's big endian or little indian. So see right here where it says read 32 Big Indian, right? That's using this special crate. We're not gonna use that we use from B E bites, but it's in host by order. Is that B E R L E. Is that big indians. Little indian. So this if we had just copied this from stack overflow, it actually would have given us um the wrong thing anybody giving us it's Yeah, sorry. Yeah. If we had tried this, it would have said okay, read it as big indian, but we need to read it as a little indian. Yeah. Alright. That should create an integer and we should be able to know print a line saying, hey, received, you know unsigned into your and print it out right here and see what we actually get. Sure I'll read the integer. Alright, let's try it. Let's try printing it. Yeah. There we go. We got an unsigned in here. So we just need to do that four times. How do we repeat something? Four times We just loop 0-4. Not inclusive boom. And if you want you to close that there we go. So yeah, this will be local to this little block right here. So no big deal on redefining these things and we need a place to store them. I'm gonna store them in a vector. So I'll say I don't know uh into jurors are like received. Imagers equals a vet, I have to say what is gonna be mutable because I'm gonna be pushing to it avec and to be empty. Beautiful. And it needs a type annotations, it's like, well a vector of what right? Like if I had started it out with vek dot from and included some values. That would be one thing. But here it has no idea what's gonna be inside of this. So I'll just give it a type right here. The vector Of unsigned, 32 bit integers. It's because it doesn't need to be mutable and it's never used but we're gonna use it right here because we get the integer and then we will say received integers that push. Sure. Alright, wonderful, wonderful. Now down here we can just use a quick print line say hey let's print it out. We're gonna print we will print our received industries, we get all four of them and then we can see they are now instead of a vector down here so now we can do whatever we need to do with that vector. So let's go back to the challenge and it says add them together and send back the results. Okay, add them together and send back the results. So all right, how do we add it together? We'll convert it to an operator so that we can then get these um mad because let me show you why cannot infer the tape. Okay, consider satisfying the type argument by doing blah blah blah. Okay, I guess. Let me see who wants this sorry, type annotation. I'm just trying to figure out is it better that's complaining or some? I guess it would be some I guess I'll say like some and then give it a tight The type would be a guess the thing that wants you to summit into like what am I something this into and we will sum it into a 32 bit integer. Let's try that again. And yeah, it's not happy. So it says the thread main panicked attempts to add with overflow. So what that means is we add up all these 32 unsigned integers and then becomes something too big to fit inside of a 32 bit unsigned integer anymore. It overflows. So there's various ways we can handle this, we could just say let it overflow and ignore the part that overflows. Um That would work. That would definitely work. Um Yeah, I guess that would work. I think what I'm gonna do is yeah. Yes, rest some allow overflow, I don't know how to do that but I wasn't gonna do is just Add them into a 64 bit integer and then convert it. So Yeah, let's see. Can you not emulate it? You can emulate it? Yeah, I don't know, Think about, you know, let's just do the way I was gonna do. So what I was gonna do is I'm actually I'm actually gonna add them in as 64 bits. Okay, So it's gonna be mad integer as u 64. Right? So I'm gonna convert them to the 64 bit integers and then this right here is going to be also a bunch of U 60 four's and I'll just add them up and Yeah, that's it, that's all, that's exactly what I'm gonna do actually when I send it back though. I think it wants me to send, Just send the results back but I'm gonna send it back also as an unsigned 32 bit integer. Just gonna convert it when I converted it will get rid of the overflow. Okay, So I get the sun now as a U- 64. So I should now be able to say let some equal that As you 32 and then let's print line to make sure that works just to see if we have something here in some that looks like it would be some. Yeah. So if you notice these are actually the some of these is clearly more than this, but what's happening is it's overflown and no longer fits into a U- 32. And we're saying, well, what part did fit? Just show us that? Yeah. Since they're giving us that error, I'm just assuming that they want us to just ignore the overflowed part. We could be wrong and if we were wrong we would send back a 64 bit. Actually, no, because in python they wouldn't call it a 64, but they would have called it a long or like a double or something. So the fact that they didn't specify it means that they probably don't want the extra part. Well, let's try sending it back now. So we'll say stream dot right? And it'll want us to write a buffer. So we're gonna have to convert this number into an array of bytes. Okay. And the way we do that is with this horrible piece of black magic. So there's actually a better way to do this basically, like what you could do as you could say here, I'll say what people that and I need to import transmute which is part of the standard library. So there's actually this this dependency we had earlier that I was showing you bite order byte order, does this for you? But I like doing it this way because then we don't have to introduce any dependencies. So we use trans mute to compute. So we want some to become like a 32 bit unsigned integer. We use transmute and then we say we wanted to post fight order or let what's it called? Uh is it called Big Endian and little Yes, a little indian. So convert it to a little Indian. bit and this is unsafe for us. We're doing things that Russ would normally prohibit. So we have to hide it inside of this unsafe and it's gonna want us to put a semi colon now, what do we write? We're gonna write to extreme this series of bytes containing our some and I did import transmutes. I don't know what it's mad about now, Says source type is a U- 32 cannot transmute between different sizes or independently sized types. Is that really true? I guess it cannot. So some interesting. Very very interesting. Let's see how did I have this before. It's the same way I was doing it. Sure. Mhm Okay. The same can't transmit between types of different sizes. That's wrong mm I'm stuck I'm stuck everybody. Yeah so let's see how am I gonna do this? Oh this isn't what this isn't what I need to actually I don't think I don't think I took a note and how to do the thing I'm about to do. It's okay we'll just look up rest convert you know in danger. Two bites. Oh oh yeah this is easy. Didn't already do this didn't already do this before this was from bites. We converted it to a number right now we want to convert it to bytes. So what we'll say as we will say The bites equal some.2 less Indian bites. Okay we write the bytes and it wants if you notice it wants a reference to it it doesn't want to take ownership. You can glad to accommodate that. We send over the bites. Now what's supposed to happen now? It says send the results to get back a user name and password so we're gonna read a string in other words so let's say string. Read to string. We have to pass it a string. Don't say let rough equal it needs to be new to book that's gonna write to it equal a string we'll give it a new string and we passed it but it's still not happy. No surprise there No 1's ever happy. What about the buffer? We should be passing mutable reference to buffer now. Happy and if we print that buffer that should give us our credentials because the answer to the challenge. So once we get those we'll try ssh again and see if it works. This is a long video isn't it? Yeah 26 minutes, wow. I have kept you all here for a long time. I apologize. We're almost done though. This is it. We're gonna see if we get the credentials they're inside of buff. So we'll go over here and say buff and we will run our code. I'm not using transmute. I don't like I don't like warnings. Alright. Use your name. Vortex one and password that I'll try that I'll say ssh with the password this um vortex one at and it says to use this host name and it gives me a ports as well so make sure to use that. He's gonna go at this sport name real quick dash P 22 to 8. And it's it's mad I think because I have a what do you call it? A half a pound sign here illegal option. Okay well we'll just copy and paste the password in which is what you should do anyway. F Y I it's like it's really bad practice to use the password on the command line as a command and option. Okay so I'm not gonna lie one over here have the password up here pasted in and welcome. We are in it has 64 bit processors, security features and naval blah blah blah. Don't please play Nice. Tell me Process Open. We're here. We're inside. We did level zero. Um, yeah, there you go. So awesome. We did it. We would now be able to move on to level one, which is about a billion times harder. But I wanted to show you all what this is about. This is vortex. It's awesome. And I hope this has been educational for you. Thank you a ton for your time. And we will talk again soon. Goodbye.
OverTheWire is the top wargame for learning computer security. And many of the challenges can be done with Rust!
OverTheWire is the top wargame for learning computer security. And many of the challenges can be done with Rust!