Understanding Proxies with SickOs 1.1

In this post I will explore the SickOs 1.1 VM by D4rk and explain how the Squid proxy enables us to access the Apache server on port 80. This isn't a walkthrough of SickOs as such but instead a deep dive into the proxy exploitation specifically. Although I knew how to compromise the VM, I realised that I didn't have it clear in my own head exactly what was going on with the proxy at the packet level and I wanted to fill in the blanks; hence this post. So we'll go through it step by step and take a look under the hood at what's really going on. 

In this article, the two IP addresses in play are:
  • 192.168.166.128: Kali (attacking machine)
  • 192.168.166.138: SickOs (victim machine)
So as we know, when we run an nmap scan we find that TCP port 3128 is open and that TCP port 80 most definitely isn't:


So for the hell of it, let's try browsing to port 80 and see what happens. Well, no surprises in Firefox; we get a long, very boring wait while it informs us that it is "Connecting to 192.168.166.138..." So let's see what that looks like in Wireshark:


Interesting. We have sent two SYN packets to SickOs in an attempt to initiate a TCP handshake, followed by twelve re-tries. You will notice that we do not get a single packet back from the target. The important thing here is that target is not completing the three-way handshake. We have no SYN-ACK back from the target because we are trying to establish a connection on an invalid TCP socket. Let's keep this in mind, and repeat the test on port 3128. 

This time we get a result in Firefox:


Ok, it's an error page but we have still got a response from the server and have verified Nmap's assessment that we are talking to a Squid proxy.  So let's compare the Wireshark trace for this with the previous one:


Very different this time. As we can see in packets 1-3, we have successfully completed the 3-way handshake and with this established, we also are then able to issue a HTTP GET request for the default page hosted on port 3128 (packet 4). The server then responds with an HTTP packet (packet 10) with an HTTP error 400 code. If we follow the TCP stream, this is what it looks like (truncated for brevity):


So all pretty standard stuff so far. As we know, the trick to compromising the box is understanding that we need to tell our browser to use Squid to proxy our requests to the real target on port 80. Hence we need to change our network preferences accordingly:


Let's pause here for a second and think about what this actually means. A proxy is an intermediary between us and our target; crucially in this case, it is allowed to ask questions that we are not. Consider the following for a moment:
  • A is allowed to talk to B, but not to C
  • B is allowed to talk to A and to C
  • C is allowed to talk to B but not to A
In our case, this translates to the following:
  • Kali is allowed to talk to Squid, but not to Apache
  • Squid is allowed to talk to Kali and to Apache
  • Apache is allowed to talk to Squid but not to Kali
The concept is nicely illustrated in the following graphic from Wikipedia:


So with our preferences changed in Firefox, let's try browsing to port 80 on the target again.


Charming. But we have now apparently magically connected to port 80. In case we're in any doubt at all about this, we can request a non-existent page and there at the bottom we can see that we're definitely talking to an Apache server on port 80:


So how is this possible? Is port 80 now open? Well, obviously not - but even so we are clearly asking to talk to port 80 and it is undoubtedly responding. How can this be? The answer of course lies in our earlier consideration of how proxies work. In our browser location bar we are most definitely asking to talk to port 80; but, as per our earlier proxy configuration settings, we are in fact asking port 3128 to talk to port 80 on our behalf behind the scenes. 

So let's take a look at the HTTP request that gets issued this time and see how it differs from an "ordinary" request to port 80. 


Now this is actually quite interesting if you think about it. There is no difference at all in the request! The browser is not, as we might expect, issuing a request to port 3128 and somehow embedding the 'real' request to port 80 inside that HTTP packet. It's just sending the request straight to port 80, as normal and as such it is indistinguishable from our earlier request to port 80 which failed. To understand this we need to revisit the OSI 7-layer model:

Layer No.Name
7Application
6Presentation
5Session
4Transport
3Network
2Data Link
1Processing

As you will no doubt recall, HTTP is an example of an application protocol at layer 7 whereas TCP is an example of a transport protocol at layer 4. So what does this have to do with anything? Well in short, it is too simplistic to consider the HTTP traffic alone. We are indeed issuing an HTTP request to port 80 and getting a proper response from that port, but the important bit happens earlier in the connection. Let's take another look at Wireshark to see what's really going on here:


So now it should be obvious how we can now magically talk to port 80. We do not, at any point, establish a connection between our attacking machine and Apache on port 80. As we know, we cannot do this; it is technically impossible. But we can and do establish a TCP connection to port 3128. This happens lower down the stack than the HTTP request (packets 1-3). As we saw earlier, the HTTP request can only be issued once the TCP socket connection has been established. Having established this connection, we now ask Squid on port 3128 to ask Apache to serve us the page available internally on port 80. Apache then sends its response to Squid and, finally, Squid returns Apache's response to us.

There is another twist to this that's also worth a closer look. Take a look at the image below:


With our proxy settings in place, we can now ... somehow ... browse the remote website on localhost! Again, check out the error message if we browse to a non-existent page:


Yep, we're definitely talking to localhost on port 80. So what black magic is this now? Through the power of our proxy have we somehow cloned the remote website, transferred it over to our local machine and started up port 80 in the background? Well, not quite. The question we have to ask ourselves here is which localhost are we talking to? Once again, this all becomes clear when we look at the problem with Wireshark.


So as we can see in packet 22, we are making a request for http://127.0.0.1/  - but crucially, we are again addressing this request to the target and not to our own local loopback address.  Just as previously, we have established a TCP session with port 3128  on the target and our request for 127.0.0.1 is being routed through that connection. So now it becomes clear why this works; "localhost" here actually means localhost in the context of our proxy connection with the target. Apache on port 80 is localhost as far as the Squid proxy on 3128 is concerned, and with our browser proxy settings changed all of our traffic is being routed through Squid. Mystery solved!

Comments

Popular posts from this blog

Buffer Overflow Fun with Brainpan 1

Real World Web Application Security Testing

Modelling Security Concepts with Archimate