SANS SCAPY Basics: Here are some common scapy commands, what they are used for, and examples of their use. ls() List protocols or your variable ls(myIP) lsc() List supported commands lsc() send() Send layer 3, no concern for response send(packet) sr1() Send layer 3, match 1 response synack=sr1(ip/syn) sr() Send layer 3 packets, match all responses sr(packets) sendp() Send layer 2, no concern for response sendp(frame) srp1() Send layer 2, match 1 response srp1(frame) srp() Send layer 2 frames, match all response srp(frames) rdpcap() Read a pcap to a list recs=rdpcap(“/tmp/pcap”) wrpcap() Write a list of packets to pcap wrpcap(“/tmp/pcap”, list) var.getlayer(protocol) Extract a layer(s) from packet ip=packet.getlayer(IP) var.payload Shows all layers after first ip.payload var.summary() Shows a summary of packet packet.summary() sniff Sniffs packets sniff(filter=”bpf”, count=2) This is how interactive scapy may be used to send a TCP SYN segment to two destination hosts, 172.22.7.133 and 172.22.10.132, to four different destination ports – 111, 139, 445, and 80. >>> sr(IP(dst=[“172.22.7.133”, “172.22.10.132”])/TCP(dport = [111, 139, 445, 80], flags=”S”)) Here is how interactive scapy may be used to craft a UDP datagram to send to destination host 172.22.7.133 and destination port 13 with some payload and listen for the response. >>> ip=IP(dst=”172.22.7.133”) >>> udp=UDP(sport=1024,dport=13) >>> payload=”All your base are belong to us” >>> packet=ip/udp/payload >>> sr1(packet) The following is a simple scapy program that creates an actual TCP session from source host 172.22.8.135 and source port 1030 to destination host 172.22.7.133 and destination port 80. It crafts the SYN segment, listens for the server’s SYN/ACK and acknowledges it to complete the three-way handshake. Next, it sends a segment that contains data. There is an issue with an undesirable side effect that creates a reset and inadvertently aborts the session. The reason and circumvention are discussed in the course. #!/usr/bin/python from scapy.all import * ip=IP(src=”172.22.8.135”, dst=”172.22.7.133”) SYN=TCP(sport=1030, dport=80, flags=”S”, seq=10) SYNACK=sr1(ip/SYN) my_ack = SYNACK.seq + 1 ACK=TCP(sport=1030, dport=80, flags=”A”, seq=11, ack=my_ack) send(ip/ACK) payload =“SENDTCP” PUSH=TCP(sport=1030,dport=80, flags=”PA”, seq=11, ack=my_ack) send(ip/PUSH/payload) ------------------- Syn Scan sr1(IP(dst="192.168.1.1")/TCP(dport=80,flags="S")) Simple Syn Packet to www.google.ch >>> sr1(IP(dst="www.google.ch")/TCP(dport=80,flags="S")) Begin emission: Finished to send 1 packets. * Received 1 packets, got 1 answers, remaining 0 packets >> >>> Fix Source Port and a List of Dest Port sr(IP(dst="192.168.1.1")/TCP(sport=666,dport=(440,443),flags="S")) Scan IP Range sr(IP(dst="192.168.1.1/24")/TCP(sport=666,dport=(25),flags="S")) Send a packet and view the answer sr(IP(dst="192.168.2.200")/TCP(sport=RandShort(),dport=[80],flags="S")) ans,unans = _ ans.summary() Results in >>> sr(IP(dst="192.168.2.200")/TCP(sport=RandShort(),dport=[80],flags="S")) Begin emission: Finished to send 1 packets. * Received 1 packets, got 1 answers, remaining 0 packets (, ) >>> ans,unans = _ >>> ans.summary() IP / TCP 192.168.2.100:61863 > 192.168.2.200:www S ==> IP / TCP 192.168.2.200:www > 192.168.2.100:61863 SA / Padding ------------------------------------------------- Creating a 3 Way Handshake Cooked vs. Raw sockets Normally, the Linux kernel takes care of setting up and sending and receiving network traffic. It automatically sets appropriate header values and even knows how to complete a TCP 3 way handshake. Uising the kernel services in this way is using a "cooked" socket. Scapy does not use these kernel services. It creates a "raw" socket. The entire TCP/IP stack of the OS is circumvented. Because of this, Scapy give us compete control over the traffic. Traffic to and from Scapy will not be filtered by iptables. Also, we will have to take care of the TCP 3 way handshake ourselves. Sending a TCP SYN We send on the wireshark or tcpdump capture following packets: - SYN (outgoing) - SYN ACK(incomming) - RST/ACK (outgonig) The RST Packet is from the Kernel, because no listen Port on the Source Port. (Scapy is not unsing RAW Socket) iptables to supress the RST iptables -A OUTPUT -p tcp --tcp-flags RST RST -s {our IP} -d {dest IP} -dport {source port} -j DROP iptables -A OUTPUT -s {our IP} -d {dest IP} -p ICMP --icmp-type port-unreachable -j DROP Replace {our IP} / {dest IP} and {source port} with your parameters TCP 3 Way Basics s_ip = IP ; s_port = port ; s_seq = seq # ; s_ack = ack # d_ip = IP ; d_port = port ; d_seq = seq # ; d_ack = ack # handshake s_ip:s_port -> d_ip:d_port, SYN, s_seq, s_ack d:ip:d_port -> s_ip:s_port, SYN/ACK, d_seq, d_ack=(s_seq + 1) s_ip:s_port -> d_ip:d_port, ACK, d_seq + 1, s_ack=(d_seq + 1) Sample Script #!/usr/bin/python from scapy.all import * ip=IP(src="10.0.0.1", dst="20.0.0.2") TCP_SYN=TCP(sport=1500, dport=80, flags="S", seq=100) TCP_SYNACK=sr1(ip/TCP_SYN) my_ack = TCP_SYNACK.seq + 1 TCP_ACK=TCP(sport=1500, dport=80, flags="A", seq=101, ack=my_ack) send(ip/TCP_ACK) my_payload="space for rent!" TCP_PUSH=TCP(sport=1500, dport=80, flags="PA", seq=102, ack=my_ack) send(ip/TCP_PUSH/my_payload) --------------------------- SCAPY ICMP Send a simple Echo Request and wait for the answer and display it. # set target ip and icmp-data ip_target = "192.168.2.200" data = "Space for Rent!" # define ip and icmp ip = IP() icmp = ICMP() # creat ip + icmp parameters ip.dst = ip_target icmp.type = 8 icmp.code = 0 a = sr1(ip/icmp/data) a.summary() and the new Scapy Ping Command (function) def ping(host, count=3): packet = IP(dst=host)/ICMP() for x in range(count): ans = sr1(packet) ans.show2() ping ("192.168.2.200",4) for sending all types and codes of icmp, simply build 2 for loops and send the packet. On the Taget side, you can sniff, what packet's are recived. # set target ip ip_target = "192.168.2.201" # define ip and icmp ip = IP() icmp = ICMP() # set the destinaion IP to the target ip.dst = ip_target # create 2 casade loops for sending the icmp packet for i_type in range(0,256): for i_code in range(0,256): icmp.type = i_type icmp.code = i_code print i_type,i_code send(ip/icmp) -------------------------------- Scapy DNS Some Scapy Samples for Testing / Flooding DNS Server with random Querys Full Random Querys for i in range(0, 1000): s = RandString(RandNum(1,50)) s1 =s.lower() d = RandString(RandNum(1,20)) d1 = d.lower() t = RandString(RandNum(2,3)) t1 = t.lower() q = s1+"."+d1+"."+t1 print i ,q send(IP(dst="192.168.0.1")/UDP(sport=RandShort())/DNS(rd=1,qd=DNSQR(qname=q))) else: print 'The for loop is over' One Domain top_level = ".ch" domain = "target" cnt = 1000 dns_server = "10.0.0.1" for i in range(0, cnt): s = RandString(RandNum(1,8)) s1 =s.lower() q = s1+"."+domain+top_level print i ,q sr1(IP(dst=dns_server)/UDP(sport=RandShort())/DNS(rd=1,qd=DNSQR(qname=q))) Some Toplevel Domains top =[ ".com", ".net" , ".com", ".edu" , ".ch", ".de", ".li", ".jp", ".ru", ".tv",".nl",".fr" ] anz_top=len(top) for i in range(0, 100): s = RandString(RandNum(1,50)) s1 =s.lower() d = RandString(RandNum(1,20)) d1 = d.lower() t = top_level=top[random.randint(0,anz_top-1)] t1 = t.lower() q = s1+"."+d1+t1 print i ,q send(IP(dst="192.168.0.1")/UDP(sport=RandShort())/DNS(rd=1,qd=DNSQR(qname=q))) else: print 'The for loop is over' DNS Enumeration Sample #!/usr/bin/python from scapy.all import * domain = "target.ch" dns_server = "10.0.0.1" server =[ "www", "www1" , "www2", "ns", "ns1" , "ns2" ,"dns" , "dns1", "dns2", "dns3", "pop", "mail", "smtp" , "pop3", "test", "dev" , "ads", "adserver", "adsl", "agent", "channel", "dmz", "sz" , "client", "imap" , "http" , "https", "ftp", "ftpserver", "tftp", "ntp" , "ids" , "ips" , "snort" , "imail" , "pops" , "imaps" , "irc" , "linux" , "windows", "log" , "install", "blog" , "host", "printer", "public" , "sql", "mysql", "router" , "cisco" , "switch", "telnet", "voip", "webmin" , "ssh", "delevlop" , "pub" , "root" , "user", "xml", "ww" , "telnet", "extern", "intranet" , "extranet", "testing" , "default", "gateway" , "radius" , "noc" , "mobile", "customer" , "chat" , "siprouter" , "sip" , "nms" , "noc", "office" , "voice" , "support" , "spare" , "owa" , "exchange" ] serverans=[] cnt=len(server) for i in range(0, cnt): q = server[i]+"."+domain ans=sr1(IP(dst=dns_server)/UDP(sport=RandShort())/DNS(rd=1,qd=DNSQR(qname=q))) ans if ans[DNS].ancount == 0: print q, "unkown" serverans.insert(i,"unkown") else: print q, ans[DNSRR].rdata serverans.insert(i,ans[DNSRR].rdata) for i in range(0, cnt): print server[i]+"."+domain, serverans[i] ---------------------------- Scapy Script sample python script with scapy inside... #! /usr/bin/env python # # execute with sudo python a.py # import sys from scapy.all import sr1,IP,ICMP p=sr1(IP(dst=sys.argv[1])/ICMP()) if p: p.show() Important Scapy Commands execute wireshark with a packet >>>whireshark(p) Display all IP flags >>> x=IP(flags=(0,7)) >>> [k for k in x] [, , , , , , , ] sniff scapy sniff with tshark like filters. a=sniff(filter="tcp port 25") or print sniffed packets a=sniff(prn = lambda x: x.display) print detail of packet a=sniff(prn = lambda x: ls(x)) or send the same packet a=sniff(filter="udp port 161") sendp(a) some other sniff samples sniff(filter="udp and port 53", count=100, iface="eth0") ---------------------------------- my Scapy IPv4 Packet crafting with Scapy for IPv4 Samples ICMP Sample a[0][0] = Send Packet a[0][1] = Recived Packet id=os.getpid() = Operatins System Call getpid >>> a,u = sr(IP(dst='192.168.2.150')/ICMP(id=os.getpid(),seq=RandShort())*25) Begin emission: .************************Finished to send 25 packets. * Received 26 packets, got 25 answers, remaining 0 packets >>> a[0][1].time - a[0][0].sent_time 0.00087618827819824219 >>> a[0][0] > >>> a[0][1] >> >>> DNS Request i=IP(dst="195.186.1.110") u=UDP(dport=53) d=DNS(rd=1,qd=DNSQR(qname="www.heise.de")) sr1(i/u/d) SNMP get p = IP(dst="192.168.2.150")/UDP(sport=161)/SNMP(community="public",PDU=SNMPget(varbindlist=[SNMPvarbind(oid=ASN1_OID("1.3.6.1.2.1.1.1.0"))])) sr1(p) SNMP set p = IP(dst="192.168.2.150")/UDP(sport=161)/SNMP(community="private",PDU=SNMPset(varbindlist=[SNMPvarbind(oid=ASN1_OID("1.3.6.1.4.1.9.2.1.55.192.168.2.100"),value="192.168.2.150.config")])) sr1(p) SNMP Cisco Transfer i=IP(src="192.168.2.100",dst="192.168.2.150")/UDP(sport=161,dport=161) s1=SNMP(community="private",PDU=SNMPset(varbindlist=[SNMPvarbind(oid=ASN1_OID("1.3.6.1.4.1.9.9.96.1.1.1.1.14.112"),value=6)])) s2=SNMP(community="private",PDU=SNMPset(varbindlist=[SNMPvarbind(oid=ASN1_OID("1.3.6.1.4.1.9.9.96.1.1.1.1.2.112"),value=1)])) s3=SNMP(community="private",PDU=SNMPset(varbindlist=[SNMPvarbind(oid=ASN1_OID("1.3.6.1.4.1.9.9.96.1.1.1.1.3.112"),value=4)])) s4=SNMP(community="private",PDU=SNMPset(varbindlist=[SNMPvarbind(oid=ASN1_OID("1.3.6.1.4.1.9.9.96.1.1.1.1.4.112"),value=1)])) s5=SNMP(community="private",PDU=SNMPset(varbindlist=[SNMPvarbind(oid=ASN1_OID("1.3.6.1.4.1.9.9.96.1.1.1.1.5.112"),value=ASN1_IPADDRESS("192.168.2.100"))])) s6=SNMP(community="private",PDU=SNMPset(varbindlist=[SNMPvarbind(oid=ASN1_OID("1.3.6.1.4.1.9.9.96.1.1.1.1.6.112"),value="chw8.txt")])) s7=SNMP(community="private",PDU=SNMPset(varbindlist=[SNMPvarbind(oid=ASN1_OID("1.3.6.1.4.1.9.9.96.1.1.1.1.14.112"),value=1)])) send(i/s1) send(i/s2) send(i/s3) send(i/s4) send(i/s5) send(i/s6) send(i/s7) NTP Fuzzing send(IP(dst="195.186.1.100")/fuzz(UDP()/NTP(version=4)),loop=1) SYN packet to port 80 of target 1.2.3.4 and some othe SYN Samples: sr1(IP(dst="1.2.3.4")/TCP(dport=80,flags="S")) sr(IP(dst="192.168.1.1")/TCP(sport=666,dport=(440,443),flags="S")) sr(IP(dst="192.168.1.1")/TCP(sport=RandShort(),dport=[440,441,442,443],flags="S")) ------------------------------ my IPv6 Scapy Samples for testing IPv6 enviroments and devices IPv6 ICMP icmp ipv6 request i=IPv6() i.dst="2001:db8:dead::1" q=ICMPv6EchoRequest() p=(i/q) sr1(p) ipv6 source route packets i=IPv6() i.dst="2001:db8:dead::1" h=IPv6ExtHdrRouting() h.addresses=["2001:db8:dead::1","2001:db8:dead::1","2001:db8:dead::1"] p=ICMPv6EchoRequest() pa=(i/h/p) Routing Header Example a = sr1(IPv6(dst="2001:4f8:4:7:2e0:81ff:fe52:9a6b")/ \ IPv6ExtHdrRouting(addresses=["2001:78:1:32::1", "2001:20:82:203:fea5:385"])/ \ ICMPv6EchoRequest(data=RandString(7)), verbose=0) a.src Traceroute waypoint = "2001:301:0:8002:203:47ff:fea5:3085" target = "2001:5f9:4:7:2e0:81ff:fe52:9a6b" traceroute6(waypoint, minttl=15 ,maxttl=34,l4=IPv6ExtHdrRouting(addresses=[target])/ICMPv6EchoRequest(data=RandString(7))) Current high score (not tested) addr1 = "2001:4830:ff:12ea::2" addr2 = "2001:360:1:10::2" zz=time.time(); a=sr1(IPv6(dst=addr2, hlim=255)/IPv6ExtHdrRouting(addresses=[addr1, addr2]*43)/ICMPv6EchoRequest(data="staythere"), verbose=0, timeout=80); print "%.2f seconds" % (time.time() - zz) ipv6 NA (version 1) sendp(Ether()/IPv6()/ICMPv6ND_RA()/ ICMPv6NDOptPrefixInfo(prefix="2001:db8:cafe:deca::", prefixlen=64)/ ICMPv6NDOptSrcLLAddr(lladdr="00:b0:de:ad:be:ef"), loop=1, inter=3) ipv6 NA (version 2) a=IPv6(nh=58, src='fe80::214:f2ff:fe07:af0', dst='ff02::1', version=6L, hlim=255, plen=64, fl=0L, tc=224L) b=ICMPv6ND_RA(code=0, chlim=64, H=0L, M=0L, O=0L, routerlifetime=1800, P=0L, retranstimer=0, prf=0L, res=0L, reachabletime=0, type=134) c=ICMPv6NDOptSrcLLAddr(type=1, len=1, lladdr='00:14:f2:07:0a:f1') d=ICMPv6NDOptMTU(res=0, type=5, len=1, mtu=1500) e=ICMPv6NDOptPrefixInfo(A=1L, res2=0, res1=0L, L=1L, len=4, prefix='2001:db99:dead::', R=0L, validlifetime=2592000, prefixlen=64, preferredlifetime=604800, type=3) send(a/b/c/d/e) The one line Router Advertisement daemon killer send(IPv6(src=server)/ICMPv6ND_RA(routerlifetime=0), loop=1, inter=1) Test1 someaddr=["2001:6c8:6:4::7", "2001:500::1035", "2001:1ba0:0:4::1", "2001:2f0:104:1:2e0:18ff:fea8:16f5", "2001:e40:100:207::2", "2001:7f8:2:1::18", "2001:4f8:0:2::e", "2001:4f8:0:2::d"] for addr in someaddr: a = sr1(IPv6(dst=addr)/ICMPv6NIQueryName(data=addr), verbose=0) print a.sprintf( "%-35s,src%: %data%") Test2 someaddr=["2001:6c8:6:4::7", "2001:500::1035", "2001:1ba0:0:4::1", "2001:2f0:104:1:2e0:18ff:fea8:16f5", "2001:e40:100:207::2", "2001:7f8:2:1::18", "2001:4f8:0:2::e", "2001:4f8:0:2::d"] for addr in someaddr: a = sr1(IPv6(dst="ff02::1")/ICMPv6NIQueryName(data="ff02::1")) print a.sprintf( "%data%") IPv6 Scapy 3 Way Creating a IPv6 3 Way Handshake Step 1. trun off the RST Packets from the Kernel, because no listen Port on the Source Port. (Scapy is not unsing RAW Socket) iptables -A OUTPUT -p tcp --tcp-flags RST RST -d {dest IP} -j DROP Step 2. Send th SYN Packet with scapy and fetch the answer. ip=IPv6(dst="2001:db8:0:1:207:3fff:fe68:df44") TCP_SYN=TCP(sport=1500, dport=80, flags="S", seq=100) TCP_SYNACK=sr1(ip/TCP_SYN) Step 3. Send the ACK Packet with scapy my_ack = TCP_SYNACK.seq + 1 TCP_ACK=TCP(sport=1500, dport=80, flags="A", seq=101, ack=my_ack) send(ip/TCP_ACK) Step 4. Check the client with netstat -na ---------------------------------- PYTHON Samples Samples tips Start and stop time and display tt=time.time() .. .. print "%.2f seconds" % (time.time() - tt) Convert a Value (INT) into Hex String Oct1 = 3 #convert int to hex oct1 = '%x'%(Oct1) #Add in leading 0 if hex string is single digit (i.e. Less than 0x10) if Oct1 < 16: oct1='''0%x'''%(Oct1) else: oct1='''%x'''%(Oct1) #Set IP options OCT1=r'\x%s'%(oct1) string converting # # Enter Oct1 - Oct4 -> Output is string # # Oct1 = 3 Oct2 = 0 Oct3 = 4 Oct4 = 255 #convert int to hex oct1 = '%x'%(Oct1) oct2 = '%x'%(Oct2) oct2 = '%x'%(Oct2) oct2 = '%x'%(Oct2) #Add in leading 0 if hex string is single digit (i.e. Less than 0x10) if Oct1 < 16: oct1='''0%x'''%(Oct1) else: oct1='''%x'''%(Oct1) if Oct2 < 16: oct2='''0%x'''%(Oct2) else: oct2='''%x'''%(Oct2) if Oct3 < 16: oct3='''0%x'''%(Oct3) else: oct3='''%x'''%(Oct3) if Oct4 < 16: oct4='''0%x'''%(Oct4) else: oct4='''%x'''%(Oct4) #Set IP options OCT_END=r'\x%s\x%s\x%s\x%s'%(oct1,oct2,oct3,oct4) Some other samples for converting >>> chr(0) '\x00' >>> struct.pack('!i', 3) '\x00\x00\x00\x03' >>> struct.pack('!i', 65535) '\x00\x00\xff\xff' Python random numbers for ipv6 i need sometimes random IP's import random for i in range(100): x = random.random() print "%x" % int(x*65536)