Hacks Archives - InputOutput.io

Lookbehind / Lookahead Regex in Vim

Here’s a nifty little vim tip for you.

I recently had to switch a few variables in PHP from $varname to $somearray['varname']. Since there were quite a few of these replacements to be done, I found it convenient to use vim’s search/replace regex feature. In this case, I have to use lookbehind, since the matching string is simply varname, and I’m not interested in catching the $ at the beginning. I just want the regex to match anything starting with the $, without having the $ as part of the matching string itself.

So, let’s try to replace the following line:

authenticate($key, $secret, $uri);

with this one:

authenticate($somearray['key'], $somearray['secret'], $somearray['uri']);

We’ll want to construct a lookbehind for the $, with some string in front. Then, we’ll replace it with $somearray['matching_string']. In vim, lookbehind uses the special @ symbol, rather than the perl (?<=somestring) syntax.

:’<,’>s/\$\@<=[a-z]\+/$somearray['&']/g

This will do the trick. As you can see, the $, @, and + must all be escaped. The lookbehind positive search chars, @<= can be replaced with @<! if a negative search is desired. Lookahead is similar to lookbehind's syntax, but uses @= and @! instead. The special & character in the replace string designates a matching token, which you can use to place the matching string in your replacement.

So for reference:

  • :%s/\(some\)\@<=thing/one/g
    

    searches for all strings starting with some, then matching thing
    changes thing into one

    end result: something becomes someone

  • :%s/\(some\)\@<!thing/one/g
    

    searches for all strings not starting with some, then matching thing
    changes thing into one

    end result: something is not changed, but everything changes to everyone

  • :%s/some\(thing\)\@=/every/g
    

    searches for all strings ending with thing, then matching some
    changes some into every

    end result: something becomes everything

  • :%s/some\(thing\)\@!/every/g
    

    searches for all strings not ending with thing, then matching some
    changes some into every

    end result: something is not changed, but someone becomes everyone

Hardening your VPN Setup with iptables

I’ll be heading out to Defcon 19 next month, so I want my VPN connection to be stable and secure.

You probably know the situation. You’re at your local coffee shop, using their (hopefully not) wide-open unsecured wifi hotspot. But you’re smart enough not to send all your data out over the clear, since there might be malicious script kiddies ready to take your sensitive data and sell it to kids on the street. So you use a VPN. You fire up OpenVPN and connect to your VPN service. Then you start browsing, comforted by the fact that your traffic is encapsulated in a secure SSL tunnel. Better yet, the user experience is transparent: you don’t have to configure your applications to manually use a SOCKS5 proxy. OpenVPN handles your routing tables and creates a virtual interface using the tun module. It’s so simple, you don’t need to think about it. But there’s a problem with this setup.

No one can reach into your stream and extract or insert data, but there’s a caveat. Anyone can destroy your TCP stream by sending you a spoofed RST packet from the remote server, or otherwise making the service unavailable to you. Destroying the TCP stream destroys the virtual (tun) interface, which, in turn, destroys the routes associated with that interface. Now you’re using your physical interface unprotected from those pesky hackers. Worse still, you don’t realize it. Not a thing has changed from the perspective of user experience. Since everything is transparent, you don’t notice any change at all. Now you’re screwed.

Little did you know that this all could have been avoided by our friend iptables. Sure, you could modify your routes further to ensure that only traffic going to the remote server goes over your physical interface, but that’s too easy. Plus, routing tables aren’t intended for security, they’re inteded to move packets along. iptables seems like the tool for the task, so I modified a script I found here to make sure that we disallow any traffic that we don’t want:

#!/bin/bash
if [[ $EUID -ne 0 ]]; then
	echo "This script must be run as root" 1>&2
	exit 1
fi

# name of primary network interface (before tunnel)
PRIMARY=wlan0

# address of tunnel server
SERVER=seattle.vpn.riseup.net
# address of vpn server
VPN_SERVER=seattle.vpn.riseup.net

# gateway ip address (before tunnel - adsl router ip address)
# automatically determine the ip from the default route
GATEWAY=`route -n | grep $PRIMARY | egrep "^0\.0\.0\.0" | tr -s " " | cut -d" " -f2`

# provided by pppd: interface name
TUNNEL=tun0

openvpn --config /my/path/to/riseup.ovpn --auth-user-pass /my/path/to/authentication.conf &

# iptables rules - important!

#LOCAL_NET=192.168.0.0/16
LOCAL_NET=$GATEWAY

# Flush all previous filter rules, you might not want to include this line if you already have other rules setup
iptables -t filter --flush

iptables -t filter -X MYVPN
iptables -t filter -N MYVPN

# Exceptions for local traffic & vpn server
iptables -t filter -A MYVPN -o lo -j RETURN
iptables -t filter -A MYVPN -o ${TUNNEL} -j RETURN
iptables -t filter -A MYVPN --dst 127.0.0.1 -j RETURN
iptables -t filter -A MYVPN --dst $LOCAL_NET -j RETURN
iptables -t filter -A MYVPN --dst ${SERVER} -j RETURN
iptables -t filter -A MYVPN --dst ${VPN_SERVER} -j RETURN
# Add extra local nets here as necessary

iptables -t filter -A MYVPN -j DROP

# MYVPN traffic leaving this host:
iptables -t filter -A OUTPUT -p tcp --syn -j MYVPN
iptables -t filter -A OUTPUT -p icmp -j MYVPN
iptables -t filter -A OUTPUT -p udp -j MYVPN

echo "nameserver 8.8.8.8" > /etc/resolv.conf

You’ll want to modify the openvpn command, interfaces, and servers to meet your needs. And that’s it! If your stream is taken down, you have these rules to protect you. I have this script as a post-connect hook for any untrusted networks I connect to (wicd is a nice network manager for adding hooks). Later, if you want your traffic to go over the clear again, you can use this script:

#!/bin/bash
if [[ $EUID -ne 0 ]]; then
	echo "This script must be run as root" 1>&2
	exit 1
fi

iptables -t filter --flush
iptables -t filter -X MYVPN

Rooting a router: Wiretapping dd-wrt / OpenWRT embedded linux firmware

Note: The following post is written partially as a follow-up to the presentation I gave on dd-wrt at the December meeting of the Western North Carolina Linux Users Group.

Concept

If you’re running dd-wrt as your router (or OpenWRT, or Tomato for that matter), you already know how powerful it can be. Capabilities such as boosting signal strength, interacting with Dynamic DNS services, running a VPN server, and transitioning to ipv6 all come prepackaged standard edition, running on a mere 4MB of flash memory (and micro running on 2MB!) What I will show you is that using the features commonly bundled with dd-wrt, you can turn your router into a wiretap, regardless of your wireless security. I’ll be dealing specifically with dd-wrt v24-sp2, but you can also wiretap OpenWRT by following similar instructions.

The idea is this: you have a router sitting at a critical juncture in your network infrastructure. Packets are rapidly being routed in and out of various interfaces on the router. If we are dealing with a wireless router with security enabled, the router is an endpoint for this encryption. Which means that the packets will be decrypted upon arrival, before being pushed through the wire. Additionally, the OpenWRT / dd-wrt communities have ported a wide array of Linux projects to the platform. Notably, they’ve ported tcpdump, the powerful command-line packet analyzer, and libpcap, the C/C++ library required for capturing network traffic. Using such a tool at the router level means your network is owned.

There’s a problem though – once we have a capture going, where do we store it? Most of these routers only have extremely limited flash storage space, usually barely enough for the embedded firmware alone. Even those that have more can only store perhaps a few moments of a heavy traffic capture. Where is all that data to go? Well, we’re in luck: dd-wrt has precompiled support for CIFS (also known as SMB), Microsoft’s network sharing protocol. If we’re able to mount a network share, and store our capture there, then we don’t have to worry about storage limitations. We can even install the packages necessary for the capture on the remote filesystem.

Implementation

Let’s start with a base install. We’ll need ssh access, so lets load up the web interface and under Services → Services enable SSHd. The package manager OpenWRT uses is called ipkg. This is not available until we enable JFFS2 under Administration → Management. Next, create a CIFS share on the local machine. Here, our local machine’s ip is 192.168.1.2, and the network share is named “share.” SSH in as root, and issue the following commands to insert the CIFS module and mount the network share:

insmod /lib/modules/2.4.35/cifs.o
mount.cifs "\\\\192.168.1.2\\share" /jffs -o user=username,password=password

Nice, now we have the network share mounted. If you encounter an error issuing the mount.cifs command, double check your ip, share name, username, and password. Since we’ve essentially mounted over the already mounted /jffs, we need to issue an additional command for ipkg to cleanly update:

mkdir -p /jffs/tmp/ipkg
ipkg update

Once ipkg has updated its package list, we can see all that is available to us by issuing:

ipkg list

As you can see, there’s a ton of stuff we can install. At this point, though, I started encountering some problems. When I issued the “ipkg install tcpdump” command, it fetched and installed the required libpcap first. Then, it went to install tcpdump, and threw an error that libpcap wasn’t installed. I tried to install them manually, but that didn’t work either. So at this point I started looking for alternatives. Optware is another way to install packages, using ipkg in /opt rather than /jffs. Following the instructions here, I created a local ext2 filesystem available via the network share:

dd if=/dev/zero of=share/optware.ext2 bs=1 count=1 seek=10M
mkfs.ext2 share/optware.ext2

If you want more space for packages, change the seek parameter. Next, we’ll be mounting this to /opt on the router side. We’ll need to install kmod-loop first, and insert the loop and ext2 kernel modules:

ipkg install kmod-loop
insmod /lib/modules/2.4.35/ext2.o
insmod /jffs/lib/modules/2.4.30/loop.o
mount -o loop /jffs/optware.ext2 /opt

Great, now we have /opt mounted to the remote ext2 filesystem. Get the install script and install it:

wget http://www.3iii.dk/linux/optware/optware-install-ddwrt.sh -O - | tr -d '\r' > /tmp/optware-install.sh
sh /tmp/optware-install.sh

Excellent, now we have the port of optware installed on /opt! Lets run an ipkg update on this ipkg:

/opt/bin/ipkg update

For comparisons sake, lets just look at how many packages we now have available, as opposed to before:

root@DD-WRT:/opt# ipkg list | wc -l
652
root@DD-WRT:/opt# /opt/bin/ipkg list | wc -l
1242

So we’ve almost doubled the amount of packages available to us. And most importantly, no more complications with tcpdump:

/opt/bin/ipkg install tcpdump

Now that we have tcpdump and libpcap, we can dump our packets to the network share:

tcpdump not host 192.168.1.2 -s 0 -w /jffs/network.cap

From here on in, we can open the packet dump with wireshark and find lots of useful information. We can even store the commands in a start-up script in the dd-wrt web interface under Administration → Commands:

insmod /lib/modules/2.4.35/cifs.o
insmod /lib/modules/2.4.35/ext2.o
mount.cifs "\\\\192.168.1.2\\share" /jffs -o user=username,password=password
insmod /jffs/lib/modules/2.4.30/loop.o
mount -o loop /jffs/optware.ext2 /opt
tcpdump not host 192.168.1.2 -s 0 -w /jffs/network.cap &

Implications

Given the wide range of routers supported by dd-wrt/OpenWRT, this is a major security concern. Although this requires physical access to the device in question, there is nothing to stop an attacker from purchasing an identical model of router, installing dd-wrt and tcpdump on it, and swapping a target router with the malicious one. If the attacker already knows the wireless password, the malicious router can be configured such a swap would not draw attention. Resetting the router is no defense – the OpenWRT firmware modification kit can easily modify the firmware image file. Modifying the image file to add code that monitors network traffic would mean that any reset would only be restoring malicious firmware.
Such an attack need not be local. Most ISPs block CIFS traffic, but the router could be made to forward the CIFS ports through an SSH tunnel to a remote endpoint. The stock Dropbear SSH isn’t capable of tunneling, but openssh is available in the ipkg repository, and can be either included in the firmware or installed on the local /jffs space available. Sending all network traffic that goes over the wire to a remote endpoint may be impractical for an attacker, but packet headers still provide a wealth of information.