Tuesday, September 22, 2009

"Hacking" out of a stateless firewall

So, when I was playing around in the kernel working on my previous entry, I found /proc/sys/net/ipv4/ip_local_port_range. The default value in my Adios sandbox VM is "32768 61000".

This is the range of ports that the kernel's TCP/IP stack will chose for the SOURCE port for new outgoing connections. That's alright, but it'd be cool if I could do something useful with it. Well, it became cool with the firewall rule my instructor wrote in my iptables class tonight.

iptables -I INPUT -i eth1 -p tcp --dport 22 -j ACCEPT #Accept incoming with a dest port of 22 - tcp
iptables -I OUTPUT -o eth1 -p tcp --sport 22 -j ACCEPT #Accept outgoing with a src port of 22 - tcp

Well, this is all well and good, a basic, stateless firewall to allow SSH clients to connect to the server.

But, it got me thinking...if I could compromise that host, then set ip_local_port_range to just port 22, I could get out, to any host/service I wanted.

So, what to do....start up a couple of VM's and try, of course!

Turns out, it actually worked. I set ip_local_port_range to "22 23" to use port 22. Screenshots to follow.


When could this be exploited? If you had a server in a DMZ. The goal of the DMZ is to isolate it from the rest of the network (workstations and internal servers). If you were using stateless filtering on the firewall from the DMZ into the enterprise network, this method could bypass that firewall. The rule you put in place to allow internal users to connect to the server, and for the server to respond, becomes the attack vector. This doesn't have to be SSH, but any port open in both directions so the clients can connect to the server - HTTP, SMTP, IMAP, POP, doesn't matter.

Note: I know, if the firewall is on the host it's useless, just disable the firewall. But if the firewall were on another machine that you can't/haven't compromised, the it comes into play. No enterprise DMZ firewall is running on their web server....I'd hope...


So, what can be done to prevent this? Use stateful packet filtering is the best. At the very least, you could add rules to not allow packets with a SYN and no ACK flag out of your DMZ. This would still leave a similar vector open for UDP attacks, and using a stateful firewall, where the states are maintained on the firewall, and not just the host, would be more secure.

Screenshots:

SSH:


HTTP connection using wget:


SSH connection in netstat, notice the source and destination port are both 22:



Addition:
The "better" rules for stateless filtering is as follows:

iptables -I OUTPUT -o eth1 -p tcp --sport 22 -j ACCEPT
iptables -I OUTPUT -o eth1 -p tcp --sport 22 --tcp-flags SYN,ACK SYN -j DROP

That second rule will not allow new connections out. If a packet has the SYN flag set without the ACK flag set, it drops it. The -I means that the rule will be inserted above the previous, and thus will match first and drop the packets.

Friday, September 18, 2009

Sending a packet to 127.0.0.1

I was sitting in my iptables class the other day, and was watctching our instructor write one of the basic firewall rules that is written every time. It is to allow all traffic in and out on the loopback.

This got me thinking - they were doing no other checks on source/dest ip at all. Pretty much every other firewall how-to I've seen does the same thing, allow loopback regardless.

Now, imagine that we took a linux box, and instead of having the loopback address being 127.0.0.1, make it something else, like 7.7.7.7 (sorry DoD). Then, add a route to 127.0.0.1, with the gateway being the remote host/router you're trying to attack.

The idea is that if you send a packet to 127.0.0.1, it will not go to the lo interface, but instead out to the host you are trying to attack. When the host relieves the packet, it would, theoretically "route" the packet to the loopback interface.

Wow, we can send a packet to the loopback address. What's the point? Say you're running a web server, and also have mysqld running on it. The smart thing to do is make mysql only listen on 127.0.0.1, so that outside users cannot access it. If we can send a packet to the host, and have it route to 127.0.0.1, we could potentially access it from the outside.

The problems:
1) This "attack" could be thwarted by a properly configured firewall.
2) You could only "attack" a host on the same subnet, since there is no way a packet destined for 127.0.0.1 would traverse a router.
3) The big one: the linux ipv4 routing implementation has sanity checks that reject (and logs) all packets with a source or destination in the 127/8 subnet block. They are "martian" packets. Check in the kernel, in net/ipv4/route.c

I'm going to have to do some more research on this topic, but I'd guess that no (modern) kernel's IP implementation would be fooled by this. I've been having problems testing, because the routing engine isn't sending packets to 127/8 addresses out over the wire. I was working on hacking the kernel to allow this for the attacker machine, but I got tired of looking though lot's of C code that I can't really understand.

Oh well, better luck next time.


On another, semi-related not:
Every address in the 127/8 block is a loopback address. You can set services to listen on 127.0.0.2, and you have to connect to them at that ip. With this, you can set services to listen on different loopback ip's, but the same port. Handy for things like running multiple we apps on the same box.