 The final challenge in Ryan Nicholson's capture-to-flag competition is called Knock Knock for 250 points in the Ninja category, the very, very last challenge kind of a culminating endgame final point here. It says, open up a TCP port by sending some data to three others in the right order. I hope you know or can Google a certain serpent-like scripting language, and it gives us a shell here that we can connect to and log in with. Same credentials like as earlier, CTF 10 and Challenge 10, and we're logged in and we can poke around on the server. However, we are trying to look at ports here, but we don't exactly know which ones. We can assume, kind of taking a look at this challenge title and the challenge prompts here, that this challenge is getting at a well-known thing called port knocking. And we can open it up in Wikipedia, try and get a better idea of it, but it's a method of externally opening ports on a firewall by generating a connection attempt on a set of pre-specified closed ports. So essentially, you knock on a bunch of different doors until one other door will open up and you can finally go through that door. We've seen this, I've seen this before in some capture-to-flag competitions, but I've never actually done it in a competition or in a game. I've never actually done this attack, so to speak. So I looked through this overview here and I looked through the benefits and stuff like this, and the explanation for this thing is that it has to be done in a brute-forced way because we don't know what ports is actually open or what ports will open. We don't know which ones are in the correct order, what three or four or whatever number of ports are necessary to knock in the correct order to open up another one. So they say here, an anonymous brute-force attack against a three-knock TCP sequence, just for example, 1000, 2000, 3000, would require an attacker to test every three-port combination in the range of all possible ports, up to 65,535, and then scan each port in between each attacks to see if there were any changes to determine, okay, have we successfully opened up another port or another door? That sucks. The average case scenario requires 141 trillion packets to determine a correct three-port number, so it's really a lot of brute-force. And what it looks like, at least on this web shell, we're kind of strapped to a web shell. We don't even have Nmap, so we've got to just use Python as the challenge prompt is alluding to here. So let's get started on something that will allow us to do that. I'm going to create a script in our challenge folder here, and in Python, we want to be able to open up different ports, right? So the way that we can do this as we normally connect to services in Python, is not using Pwn tools, but using something built in or kind of live off the land since we're going to be connecting and doing this on their web shell, doing it local to this challenge server. So we can use the Socket library that's built into Python. We can import Socket, and then I'll open up the documentation online, Python Socket. Check out the documentation here. Scroll down to the very, very end because they do give us some examples, and we can just get basic boilerplate code to connect to some host and do some things with it. So we're just going to be connecting to our local host. So let's just change that to 127.001. And the port will be a variable, right? Because let's actually create a function, a general purpose function that will allow us try a port and see if we can connect to it and then do whatever we need to do from that. We can make a connection here and then actually try, and we don't need to send anything to it, but we can try and receive data. It will need some number, but let's just bump this up to 4096. And if we actually receive something, then, okay, we successfully connected to it. If not, whatever. So let's, for one thing, determine if we're actually making a connection. Let's try this on a local thing. Let's try, if we return the data, how about that? We'll print to try port on our own, like, elites or whatever port number we particularly want to try. I've got it in our folder here, so I can run this. And, okay, we have to actually specify the port in, as an argument, sorry. And we get a connection refused in this case. So let's put this in a try statement. Let's try and then let's accept. And we can, if we get a socket error, we know that, okay, we are not connecting. So we can print, port is closed. Got that? Port is closed. And let's return out of this now because we don't want to do anything else. So, okay, that fails for us. Cool, let's try it on a port that actually is open. So let's just create a simple HTTP server like on port 80 or how about 999? So now we have something that we can actually connect to that has some success to it. We'll change that to 999. Try and run this and nothing is going to be received. So, but we've got a connection. It isn't breaking immediately. So let's set a timeout here. We can actually do this, checking out the documentation. If we just look at timeout, we have a function called setTimeout. And let's set that to something super duper small. So we've got a socket.setTimeout. Do we do it for that socket object? Or do we do it for the entire library? Let's find out 0.1. Let's try one more time. Okay, no, so it must be in that object. So our socket connection, we will create a timeout for. Got a second period there. Now let's try it and we get a socket timeout. Okay, so we can try and do this, receive data. And if we do receive data, we can say print port is open received. And then how about the data that we're actually looking for cool. Else or except, sorry, except socket timeout. We can print port is open, but timed out cool. And then we'll return. Actually, we don't need to worry about that because we should already be able to connect. Let's try that. And we don't need data. Actually, we can just set it to an empty string. Port is open, but timed out. Okay, so that one works when we were hosting something here or it's close when we turn off our HTTP server. Cool. So now we have a basic try to connect to a port function that we've got testing and working locally. Let's build out a scan function though because we don't want to be able to try ports all the way up to 65,535, right? So let's actually get some Boolean things to be occurring here. So let's get like, if the port is closed, we'll return false. And if the port is actually open, we can return true, right? And if it is true, again, port is open, but we're timing out. Again, we can return true. And then I guess socket close will go through, etc. In those actual things where we do return, we're actually connecting. We're actually making connections, so we don't need data anymore. So whatever simple try port functionality that we've got here probably won't need these print statements anymore. Now let's just build a general purpose scan function where we can scan and then for I in range or for port in range all the way from one to 65,535. Let's try port and then let's actually keep track of a list here. Let's say found ports can be just like this. So connected equals try port port. And if connected, we can found ports dot append that port that we're looking at at the moment. So after we're done that, we can return all of the found ports after we have completed our scan. So now we can try and print out the scan that we run and let's do it take a little bit of time running on my local system. But OK, these are all the ports that I have running just now on my system. For whatever reason, some of those may be doing strange things. I don't know, whatever, maybe I'm an insecure guy doing security stuff. But OK, some ephemeral ports, whatever, that works just fine. We have a basic scan function now. So let's try this on the actual box that we want. We can do this in the web shell. What I'm going to do is to actually get this over there. I can't just copy and paste this like I would want to. Like if I opened up Vim, if I wanted to create a new whatever, whatever document. If I wanted to paste into it, I'd still have to paste from browser, which gives me only a simple like singular input box. So that sucks. Let's be smarter and base 64 decode this stuff. Let's transfer it in a pretty cool and easy way. Let's base 64 the attacker, remove all of these new lines and let's put that in our clipboard. Cool. So now in the shell, I can echo this guy that we paste from our browser into base 64 dash decode. And now we've got it all. We can redirect it to attacker.py. Sure. So now let's run Python attacker.py. We've already tested it. We know it'll do stuff. And we see these ports 10,337 open. So that's interesting. 10,000 and elite. Interesting. Nothing else. Since our script is just running a scan, let's run a scan again. And then we're seeing interesting thing 4444, 10,337 again, but other some other interesting things, 52342, whatever. And I kept scanning for a little bit just because I wanted to get an idea. And I noticed that some of the ports are starting to go away. And we're getting some strange ephemeral ports or like 53584. Other things that we had not seen previously and are again, 40,000 other things that looks like the ports that we had seen before suddenly aren't there anymore. Even no ports are open at some point. So this was kind of behaving strangely in my opinion. So I kind of wanted to do this in a little bit of an interesting way. What I did as I was exploring these is I was going through possible permutations of all these ports. So if you wanted to, you could import iter tools and then for iter tools for like possible in iter tools dot permutations or combinations or whatever the case may be of, let's see, we want range of one and two, six, five, five, five, three, five, and we want three of them. So that will be our other argument we can print out here. So let's print out whatever possible order that may be in our in our triple order of port knocking and that would work through. Okay, these are the orders that we're going to try knocking on ports and that will take a long time. And that's obviously maybe not the best thing. However, we saw when we ran our first scan that, okay, we'll only have 10,000 and 3137 open. And interestingly enough, that 444 showed it, but these two showed again and then it never ran through one more time. So I thought this was very strange and I kept tinkering with it and realizing that I was being I was I was losing that opportunity with those three ports and it seemed like that was only happening. Those were only available at the very, very start of a new shell. So I tried this over and over again and I'd try to bring over a script and I'd try and scan and I'd look at again that it's those couple of ports that are open, 10,000, 3137, 444. So I tried to connect to those in that specific order and that got me some nothing, nothing particularly interesting and I actually kind of did that by hand in a strange way. What I had done was I created a simple script called triport that would just do the exact same thing as this triport function. I would do it kind of one by one. So I would import sys and then I would try and display this output here and I don't need to scan function in this script, but I would try and run triport with sys.argv1. So I would give this script an argument and I would get to see, okay, the port is open, blah, blah, blah. So let's try this just as a single script here. Let's cat triport into basic, well, let me make sure that actually works for us. Python triports 9999, it should be closed. Ah, so it needs that as an integer. Good thing that we tried that before we brought it over. Cool, port is closed. Okay, so let's base 64 that and then remove all the new lines so we can transfer it over a okay, put it in our clipboard and then now we are in a new, a new session. So let's paste in the browser, bring that to base64 decode, put it to triport.py and then I would run Python triport and 10,000 was what I want to look at. It says port is open but timed out and that happens continually except it got closed after a little bit. So interesting thing. If I wanted to scan after that I could and I would just create a simple scan script if I wanted to. So I could do that from the command line following a simple attacking or looking at that port. Again, I would just create a new script where I don't need Sysfee 1 anymore but I can just try and run scan and I would print scan and call that scan.py copied over as I need to and I wouldn't need that output in this one. I just want to get the boolean variable. Is this port open or not? So if I wanted to copy that over I certainly could but this is where in my mind something triggered because I was seeing these weird results where the port was open for 10,000 and 31337 elite 444 but it was timing out and I didn't know why. So it must be trying to do something. It must have existed there for for a reason. So I went back to the challenge prompt and I realized open a TCP port by sending it some data. That means that I have to actually like send it something or tell that port that I'm I'm actually trying to connect to it. It's not just open a port and move on for this port knocking attack. It's actually actually send something to it. So I modified my try port script and I would try if it were open, I would try and send stuff to it. I would try to run s dot send line like a or whatever. That is a thing I can do right. I can run send line or just send s dot send send all. Okay. So let's just send and how about a new line or something? Perfect. Cool. Let's try and copy that. Now I can bring it over and let's create a new session. So that 10,000 is still available and 3137 etc. And that was a strange and interesting thing that it had to happen just at a start of a fresh web web shell connection. So echo paste from browser get our code over there. Bring it to try port dot pi and then I would Python try port 10,000 and it said port is open received getting warm. Huh. I thought that was really weird. So I tried again. I tried. Okay. Let's try that one, but it didn't work. Huh. What about that port that we saw? Otherwise 3133 port is open getting warmer. Okay. And the other port that came up following that was 444 right 4444 getting that it says almost there. So I thought, okay, this must be it. It would be whatever port would open following those right at this point. I could scan and see what next port is available. I think it was that 31984 whatever just to be sure we can copy over our scan since we created that as a script to let's echo that paste it from browser base 64 tack D to scan dot pi. We can run scan dot pi and 31984 is another option. So let's try and run Python try port on 31984. Port is closed. Huh. Okay. Why did that happen? Well, we already knocked on all these other ports. It looks like it's as if we've ruined our sequence because we ran through a different scan. So we'd have to know the port in the correct order and then go through that whole knock sequence one more time. So let's do that new session. So these ports are are fresh for us and then let's get our try port available pass that through try port dot pi and then we can Python try port. We know 10,000 is the first one getting warm and then it was the elite getting warmer 444. Almost there and then it was 31984 flag. Glyptography cool. We did it. That was awesome. I think that was a little bit of learning a little bit understanding a little bit of tinkering. It took me a while to at least for one thing figure out. Okay. I can transfer these scripts through base 64. I can write them and test them on my own box and then I would kind of tinker with just those ports and I thought they were very peculiar because obviously elite should have some meaning. 10,000 is pretty. Yeah, it's not. It doesn't look like an ephemeral port, right? It's not just some random number. Same thing with 444. So it looked like that was just the next option as 31984 would always seem to come following all those other ports that we were trying. So cool interesting challenge and really cool attack and it was cool to be able to write that and really go through and explore it in Python. So I hope you guys enjoyed that. I hope you had a lot of fun with it and that is how you can jump up to like a thousand points on Ryan CTF awesome game. Thank you so much, Ryan Nicholson submit that flag and just jump to the top. Cool. We can mark that again if we wanted to as the flag in our own notes, but what I want to do is show some love to the people that support me on patreon. So all of these individuals you are the best people ever like literally every single one of you is the best all of you at the same time. Hey $1 a month on Patreon will give you a special shout out at the end of every video just like this. $5 a month on Patreon will give you early access to everything that release on YouTube just like this video as soon as it's ready not when YouTube wants to because I normally record in mass or in bulk and then gradually slowly release things on YouTube. So if you want the content right when it's ready right when it's hot just ready to be watched and the video is done recording you can do that just $5 a month. Hey, if you did like this video please do like maybe leave me a comment subscribe if you're willing and please join the discord server link in the description and if you're willing to support me on patreon you know I love that. Hey, I'll see you soon.