Hello and welcome to this course in which we're talking about using Python for command and control or C2. In this video, we're going to talk about using Python for protocol tunneling. What protocol tunneling means is sending another channel of data over a different protocol. You can use a variety of different protocols for protocol tunneling. In this particular demonstration, we're going to be using HTTP as the protocol to carry our actual C2 connection traffic. We're going to be implementing this using a client and server code that you can see on the screen now. How we're going to implement our protocol tunneling is via the cookie values in HTTP requests and the data carried by an HTTP response. Let's start out by taking a look at our client code on the left. For this, we're going to be using the requests library to actually create our request, send it, get responses, etc. Then we're going to be using the base64 library for encoding the data that we're sending. When we're using base64, we're making sure that our actual messages that we're sending are not revealed in plain text, and so that's an asset. However, base64 is not an encryption algorithm, it's an encoding algorithm, and the important difference here is that an encoding algorithm like base64 is easily reversible by anyone who sees the traffic because there's no secret key involved, the protocol's well-known and documented. So anyone who actually digs into our C2 traffic in this case, has the ability to read the data that we're transmitting over it. However, base64 encoding makes that data a little bit more difficult to find. How we're going to be implementing the client is very simple. We're just going to create a C2 function here that takes a target URL and the data to be transmitted. We're going to use the request library to create a GET request to that particular URL and then we're going to define one header in our HTTP request, and that's a cookie value. Cookies, as we know, are commonly used to store authentication information and other state information for a user session on a website. It's not uncommon for cookies to contain base64-encoded data that may include encrypted data or other sensitive data from the site. In hiding our C2 traffic in base64-encoded cookies, might not be an immediately evident C2 channel to someone taking a look at this traffic. We'll define that cookie header value and provide base64-encoded data as the value of the cookie. This is a bit of a bare-bones implementation of the client. We definitely could add additional header information, flesh out our request, etc., to make this look a little bit more realistic. We could include except encodings, user agents, etc., to make the request look more like a standard user HTTP request. However, this at least demonstrates how we can make sure that our traffic is carried over the HTTP protocol, again, without being immediately evident. The URL we're going to be accessing is on the localhost 127.0.0.1 and port 8443. We haven't really specified anything beyond there regarding a particular page, but again, we could do so to make that look more realistic. We're going to have the data that we're sending be the string "C2 data", and then we just need to UTF-8 encode it and put it in bytes for it to be base64 encoded later. Finally, we'll call our C2 function with our defined URL and data to transmit. That's really all there is to the client-side of our code. On the server-side, we have a little bit more complexity. So let's start down at the bottom here in our main function. In our main function, we're going to define our hostname as localhost and the port as 8443. We'll then create a webserver of type HTTP server. We're going to provide the hostname and port and then we'll provide a function called C2 server that we've got defined up above to actually handle the requests to that webserver. After we've created the webserver, we're going to have it be served forever until there's a keyboard interrupt, in which case it will tear down the webserver and close it. Because we're using the http.server library here in its built-in base, HTTP request handler, and HTTP server functionality, creating this webserver is pretty simple. This simple call and a few commands to serve it is all we need for a functional webserver. What it doesn't provide is the actual implementation of request handling, which is what we're doing up here. So our webserver here is designed to only accept GET requests or we've only defined a GET handling function, which we have here with doGet. Since we know that our base64-encoded C2 data is included in the cookie header, we need to parse the headers to actually get the data that we're being sent. So starting here, we see that we can access these headers with self.headers, and we can request the one associated with cookie. We then b64 decode that to get the original message. We use.decode UTF-8 to go from bytes to a string and then we use rstrip to remove any trailing whitespace from it. At the end, we'll have the data that we transmitted, C2 data, which we'll be able to print out here with received, and then we can also implement functionality in the server to take action based off of what data it receives. So if the data that we've received is the C2 data that we expected, we can send an acknowledgment message. Our response would be a base64-encoded version of the word received, encoded using UTF-8. We're then going to send a 200 response saying that, "Okay, the request was received. Here's the response." We'll say that we're ending the headers there and then we can use self.wfile.write to write the actual body of the response that we're sending. In this case, we're not sending a full HTML page. We're just going to send some text data, and that's the base64-encoded version of the response. Again, like the client, this is a bit bare bones and might be fairly obvious to detect. However, you can certainly take additional action to flesh out the headers, embed the data that you're sending somewhere in the response, etc. To make this webserver and C2 communication a little bit harder to, say, reverse engineer, we've set it up so that it only is going to accept that one message. Any other time it's not going to respond with received. It's going to send a 404 error saying, "Page not found." This is just designed to make it a little bit harder to reverse engineer. Here we've got a client and a server that implement protocol tunneling using HTTP requests, cookies, and then the data contained within an HTTP response. Now let's see this code actually running. Minimize this. We'll run the server here in the left-hand window, and so now it's going to continuously serve connections. So if we call it with our client code, hit enter here, we've transmitted the C2 data, and so based off of its analysis, it saw that this matched the response that I was expecting, and so it's stating here that it received a GET request and so it sent a 200 response. Embedded in that 200 response was the message, "Received," base64 encoded, which the client receives, decodes, and then prints here on the command line. This demonstration was designed to illustrate the use of protocol tunneling over HTTP using base64-encoded cookies and data. While this was a bit of a bare-bones example of the client and the server, I mentioned it's certainly possible to flesh out both of them to make it look more realistic and more difficult to detect. Thank you.